Disabled external gits
This commit is contained in:
38
cs320-clp/test/scala/amyc/test/CodegenTests.scala
Normal file
38
cs320-clp/test/scala/amyc/test/CodegenTests.scala
Normal file
@@ -0,0 +1,38 @@
|
||||
package amyc.test
|
||||
|
||||
import java.io.ByteArrayInputStream
|
||||
|
||||
import amyc.analyzer.{NameAnalyzer, TypeChecker}
|
||||
import amyc.codegen._
|
||||
import amyc.parsing._
|
||||
import amyc.utils._
|
||||
import amyc.wasm.Module
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
import scala.sys.process._
|
||||
|
||||
class CodegenTests extends ExecutionTests {
|
||||
|
||||
object CodePrinterExecutor extends Pipeline[Module, Unit] {
|
||||
def run(ctx: Context)(m: Module) = {
|
||||
CodePrinter.run(ctx)(m)
|
||||
val fileName = s"${m.name}.js"
|
||||
|
||||
// Consume all standard input!
|
||||
val input = Console.in.lines.iterator().asScala.toList.mkString("\n")
|
||||
val inputS = new ByteArrayInputStream(input.getBytes("UTF-8"))
|
||||
|
||||
val exitCode = s"nodejs wasmout/$fileName" #< inputS ! ProcessLogger(Console.out.println, Console.err.println)
|
||||
if (exitCode != 0)
|
||||
throw AmycFatalError("Nonzero code returned from nodejs")
|
||||
}
|
||||
}
|
||||
|
||||
val pipeline =
|
||||
Lexer andThen
|
||||
Parser andThen
|
||||
NameAnalyzer andThen
|
||||
TypeChecker andThen
|
||||
CodeGen andThen
|
||||
CodePrinterExecutor
|
||||
}
|
93
cs320-clp/test/scala/amyc/test/CompilerTest.scala
Normal file
93
cs320-clp/test/scala/amyc/test/CompilerTest.scala
Normal file
@@ -0,0 +1,93 @@
|
||||
package amyc.test
|
||||
|
||||
import java.io.File
|
||||
import java.util.stream.Collectors
|
||||
|
||||
import amyc.utils._
|
||||
import org.junit.Assert.fail
|
||||
|
||||
abstract class CompilerTest extends TestUtils {
|
||||
private def runPipeline(pipeline: Pipeline[List[File], Unit], fileNames: List[String]) = {
|
||||
val ctx = Context(new Reporter, fileNames)
|
||||
val files = ctx.files.map(new File(_))
|
||||
pipeline.run(ctx)(files)
|
||||
ctx.reporter.terminateIfErrors()
|
||||
}
|
||||
|
||||
private def runPipelineRedirected(
|
||||
pipeline: Pipeline[List[File], Unit],
|
||||
compiledFiles: List[String],
|
||||
input: String
|
||||
): String = {
|
||||
testWithRedirectedIO(runPipeline(pipeline, compiledFiles), input)
|
||||
}
|
||||
|
||||
private def assertEqual(output: String, expected: String) = {
|
||||
val rejectLine = (s: String) =>
|
||||
s.isEmpty ||
|
||||
s.startsWith("[ Info ]") ||
|
||||
s.startsWith("[Warning]") ||
|
||||
s.startsWith("[ Error ]") ||
|
||||
s.startsWith("[ Fatal ]")
|
||||
def filtered(s: String) = s.lines.filter(rejectLine(_)==false).collect(Collectors.joining("\n"));
|
||||
val filteredOutput = filtered(output)
|
||||
val filteredExpected = filtered(expected)
|
||||
if (filteredOutput != filteredExpected) {
|
||||
val sb = new StringBuffer()
|
||||
sb.append("\nOutput is different:\n")
|
||||
sb.append("\nOutput: \n")
|
||||
sb.append(filteredOutput)
|
||||
sb.append("\n\nExpected output: \n")
|
||||
sb.append(filteredExpected)
|
||||
sb.append("\n")
|
||||
fail(sb.toString)
|
||||
}
|
||||
}
|
||||
|
||||
protected def compareOutputs(
|
||||
pipeline: Pipeline[List[File], Unit],
|
||||
compiledFiles: List[String],
|
||||
expectedFile: String,
|
||||
input: String = ""
|
||||
) = {
|
||||
try {
|
||||
val output = runPipelineRedirected(pipeline, compiledFiles, input)
|
||||
val expected = scala.io.Source.fromFile(new File(expectedFile)).mkString
|
||||
assertEqual(output, expected)
|
||||
} catch {
|
||||
// We only want to catch AmyFatalError gracefully, the rest can propagate
|
||||
case AmycFatalError(msg) =>
|
||||
fail(s"\n $msg\n")
|
||||
}
|
||||
}
|
||||
|
||||
protected def demandPass(
|
||||
pipeline: Pipeline[List[File], Unit],
|
||||
compiledFiles: List[String],
|
||||
input: String = ""
|
||||
) = {
|
||||
try {
|
||||
runPipelineRedirected(pipeline, compiledFiles, input)
|
||||
} catch {
|
||||
case AmycFatalError(msg) =>
|
||||
fail(s"\n $msg\n")
|
||||
}
|
||||
}
|
||||
|
||||
protected def demandFailure(
|
||||
pipeline: Pipeline[List[File], Unit],
|
||||
compiledFiles: List[String],
|
||||
input: String = ""
|
||||
) = {
|
||||
try {
|
||||
runPipelineRedirected(pipeline, compiledFiles, input)
|
||||
fail("Test should fail but it passed!")
|
||||
} catch {
|
||||
case AmycFatalError(_) =>
|
||||
// Ok, this is what we wanted. Other exceptions should propagate though
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
15
cs320-clp/test/scala/amyc/test/ExecutionTests.scala
Normal file
15
cs320-clp/test/scala/amyc/test/ExecutionTests.scala
Normal file
@@ -0,0 +1,15 @@
|
||||
package amyc.test
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
abstract class ExecutionTests extends TestSuite {
|
||||
|
||||
val baseDir = "interpreter"
|
||||
|
||||
val outputExt = "txt"
|
||||
|
||||
@Test def testEmptyObject = shouldOutput("EmptyObject")
|
||||
|
||||
@Test def testMinimalError = shouldFail("MinimalError")
|
||||
|
||||
}
|
17
cs320-clp/test/scala/amyc/test/LexerTests.scala
Normal file
17
cs320-clp/test/scala/amyc/test/LexerTests.scala
Normal file
@@ -0,0 +1,17 @@
|
||||
package amyc.test
|
||||
|
||||
import amyc.parsing._
|
||||
import org.junit.Test
|
||||
|
||||
class LexerTests extends TestSuite {
|
||||
val pipeline = Lexer andThen DisplayTokens
|
||||
|
||||
val baseDir = "lexer"
|
||||
|
||||
val outputExt = "txt"
|
||||
|
||||
@Test def testKeywords = shouldOutput("Keywords")
|
||||
|
||||
@Test def testSingleAmp = shouldFail("SingleAmp")
|
||||
|
||||
}
|
44
cs320-clp/test/scala/amyc/test/NameAnalyzerTests.scala
Normal file
44
cs320-clp/test/scala/amyc/test/NameAnalyzerTests.scala
Normal file
@@ -0,0 +1,44 @@
|
||||
package amyc.test
|
||||
|
||||
import amyc.analyzer.{NameAnalyzer, SymbolTable}
|
||||
import amyc.ast.SymbolicTreeModule.Program
|
||||
import amyc.ast.{Identifier, SymbolicPrinter}
|
||||
import amyc.parsing._
|
||||
import amyc.utils._
|
||||
import org.junit.Test
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
class NameAnalyzerTests extends TestSuite {
|
||||
// A little hackery to overcome that Identifier names do not refresh over pipeline runs...
|
||||
private class TestUniquePrinter extends SymbolicPrinter {
|
||||
private val counter = new UniqueCounter[String]
|
||||
private val map = scala.collection.mutable.Map[Identifier, Int]()
|
||||
override implicit def printName(name: Identifier)(implicit printUniqueIds: Boolean): Document = {
|
||||
if (printUniqueIds) {
|
||||
val id = map.getOrElseUpdate(name, counter.next(name.name))
|
||||
s"${name.name}_$id"
|
||||
} else {
|
||||
name.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val treePrinterS: Pipeline[(Program, SymbolTable), Unit] = {
|
||||
new Pipeline[(Program, SymbolTable), Unit] {
|
||||
def run(ctx: Context)(v: (Program, SymbolTable)) = {
|
||||
println((new TestUniquePrinter)(v._1)(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val pipeline = Lexer andThen Parser andThen NameAnalyzer andThen treePrinterS
|
||||
|
||||
val baseDir = "nameAnalyzer"
|
||||
|
||||
val outputExt = "scala"
|
||||
|
||||
@Test def testParamAndLocal = shouldOutput("ParamAndLocal")
|
||||
|
||||
@Test def testArgumentNumberFunction = shouldFail("ArgumentNumberFunction")
|
||||
}
|
18
cs320-clp/test/scala/amyc/test/ParserTests.scala
Normal file
18
cs320-clp/test/scala/amyc/test/ParserTests.scala
Normal file
@@ -0,0 +1,18 @@
|
||||
package amyc.test
|
||||
|
||||
import amyc.parsing._
|
||||
import org.junit.Test
|
||||
|
||||
class ParserTests extends TestSuite with amyc.MainHelpers {
|
||||
val pipeline = Lexer andThen Parser andThen treePrinterN("")
|
||||
|
||||
val baseDir = "parser"
|
||||
|
||||
val outputExt = "scala"
|
||||
|
||||
@Test def testEmpty = shouldOutput("Empty")
|
||||
@Test def testLiterals = shouldOutput("Literals")
|
||||
|
||||
@Test def testEmptyFile = shouldFail("EmptyFile")
|
||||
}
|
||||
|
54
cs320-clp/test/scala/amyc/test/TestSuite.scala
Normal file
54
cs320-clp/test/scala/amyc/test/TestSuite.scala
Normal file
@@ -0,0 +1,54 @@
|
||||
package amyc.test
|
||||
|
||||
import java.io.File
|
||||
|
||||
import amyc.utils.Pipeline
|
||||
|
||||
abstract class TestSuite extends CompilerTest {
|
||||
val pipeline: Pipeline[List[File], Unit]
|
||||
|
||||
val baseDir: String
|
||||
lazy val effectiveBaseDir: String =
|
||||
// getClass.getResource(s"/$baseDir").getPath
|
||||
s"test/resources/$baseDir"
|
||||
|
||||
val passing = "passing"
|
||||
val failing = "failing"
|
||||
val outputs = "outputs"
|
||||
|
||||
val outputExt: String
|
||||
|
||||
def shouldOutput(inputFiles: List[String], outputFile: String, input: String = ""): Unit = {
|
||||
compareOutputs(
|
||||
pipeline,
|
||||
inputFiles map (f => s"$effectiveBaseDir/$passing/$f.scala"),
|
||||
s"$effectiveBaseDir/$outputs/$outputFile.$outputExt",
|
||||
input
|
||||
)
|
||||
}
|
||||
|
||||
def shouldOutput(inputFile: String): Unit = {
|
||||
shouldOutput(List(inputFile), inputFile)
|
||||
}
|
||||
|
||||
def shouldFail(inputFiles: List[String], input: String = ""): Unit = {
|
||||
demandFailure(
|
||||
pipeline,
|
||||
inputFiles map (f => s"$effectiveBaseDir/$failing/$f.scala"),
|
||||
input
|
||||
)
|
||||
}
|
||||
|
||||
def shouldFail(inputFile: String): Unit = {
|
||||
shouldFail(List(inputFile))
|
||||
}
|
||||
|
||||
def shouldPass(inputFiles: List[String], input: String = ""): Unit = {
|
||||
demandPass(pipeline, inputFiles map (f => s"$effectiveBaseDir/$passing/$f.scala"), input)
|
||||
}
|
||||
|
||||
def shouldPass(inputFile: String): Unit = {
|
||||
shouldPass(List(inputFile))
|
||||
}
|
||||
|
||||
}
|
24
cs320-clp/test/scala/amyc/test/TestUtils.scala
Normal file
24
cs320-clp/test/scala/amyc/test/TestUtils.scala
Normal file
@@ -0,0 +1,24 @@
|
||||
package amyc.test
|
||||
|
||||
import java.io._
|
||||
|
||||
/** Some utilities for running tests */
|
||||
trait TestUtils {
|
||||
/** Run test,
|
||||
* with input also redirected from a String,
|
||||
* and output is redirected to a local StringBuilder.
|
||||
*/
|
||||
def testWithRedirectedIO[T](test: => T, input: String): String = {
|
||||
import scala.Console._
|
||||
val inputS = new StringReader(input)
|
||||
val outputS = new ByteArrayOutputStream()
|
||||
withOut(outputS) {
|
||||
withErr(outputS) {
|
||||
withIn(inputS) {
|
||||
test
|
||||
}
|
||||
}
|
||||
}
|
||||
outputS.toString()
|
||||
}
|
||||
}
|
25
cs320-clp/test/scala/amyc/test/TyperTests.scala
Normal file
25
cs320-clp/test/scala/amyc/test/TyperTests.scala
Normal file
@@ -0,0 +1,25 @@
|
||||
package amyc.test
|
||||
|
||||
import amyc.analyzer.{NameAnalyzer, TypeChecker}
|
||||
import amyc.parsing._
|
||||
import amyc.utils._
|
||||
import org.junit.Test
|
||||
|
||||
class TyperTests extends TestSuite {
|
||||
// We need a unit pipeline
|
||||
private def unit[A]: Pipeline[A, Unit] = {
|
||||
new Pipeline[A, Unit] {
|
||||
def run(ctx: Context)(v: A) = ()
|
||||
}
|
||||
}
|
||||
|
||||
val pipeline = Lexer andThen Parser andThen NameAnalyzer andThen TypeChecker andThen unit
|
||||
|
||||
val baseDir = "typer"
|
||||
|
||||
val outputExt = "" // No output files for typechecking
|
||||
|
||||
@Test def testArithError1 = shouldFail("ArithError1")
|
||||
|
||||
@Test def testArithmetic = shouldPass("Arithmetic")
|
||||
}
|
Reference in New Issue
Block a user