package wacc import org.scalatest.{ParallelTestExecution, BeforeAndAfterAll} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.Inspectors.forEvery import java.io.File import sys.process._ import java.io.PrintStream import scala.io.Source class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll with ParallelTestExecution { val files = allWaccFiles("wacc-examples/valid").map { p => (p.toString, List(0)) } ++ allWaccFiles("wacc-examples/invalid/syntaxErr").map { p => (p.toString, List(100)) } ++ allWaccFiles("wacc-examples/invalid/semanticErr").map { p => (p.toString, List(200)) } ++ allWaccFiles("wacc-examples/invalid/whack").map { p => (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) assert(expectedResult.contains(result)) } if (expectedResult == List(0)) it should "run with correct result" in { if (fileIsDisallowedBackend(filename)) pending // 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).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") val exitLineIdx = contents.indexWhere(_.matches("^# ?[Ee]xit:.*$")) val expectedExit = if (exitLineIdx == -1) 0 else contents(exitLineIdx + 1).stripPrefix("#").strip.toInt // Assembly and link using gcc val asmFilename = baseFilename + ".s" val execFilename = baseFilename val gccResult = s"gcc -o $execFilename -z noexecstack $asmFilename".! assert(gccResult == 0) // 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 = _ => () ) assert(process.exitValue == expectedExit) assert(stdout.toString == expectedOutput) } } def allWaccFiles(dir: String): IndexedSeq[os.Path] = val d = java.io.File(dir) os.walk(os.Path(d.getAbsolutePath)).filter { _.ext == "wacc" } 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 }