From a5966f9858fc624516d88ca30cedd83e6e7870a3 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 12 Jul 2022 15:05:05 +0100 Subject: [PATCH] Cleanup BashExitCodeTests --- .../exit-code-tests/compileError.scala | 1 - .../exit-code-tests/positiveTest.scala | 1 - .../exit-code-tests/runtimeError.scala | 1 - .../exit-code-tests/scriptCompileError.sc | 1 - .../exit-code-tests/scriptPositive.sc | 1 - .../exit-code-tests/scriptRuntimeError.sc | 1 - .../tools/scripting/BashExitCodeTests.scala | 229 ++++-------------- 7 files changed, 53 insertions(+), 182 deletions(-) delete mode 100644 compiler/test-resources/scripting/exit-code-tests/compileError.scala delete mode 100644 compiler/test-resources/scripting/exit-code-tests/positiveTest.scala delete mode 100644 compiler/test-resources/scripting/exit-code-tests/runtimeError.scala delete mode 100644 compiler/test-resources/scripting/exit-code-tests/scriptCompileError.sc delete mode 100644 compiler/test-resources/scripting/exit-code-tests/scriptPositive.sc delete mode 100644 compiler/test-resources/scripting/exit-code-tests/scriptRuntimeError.sc diff --git a/compiler/test-resources/scripting/exit-code-tests/compileError.scala b/compiler/test-resources/scripting/exit-code-tests/compileError.scala deleted file mode 100644 index d703006dc2d4..000000000000 --- a/compiler/test-resources/scripting/exit-code-tests/compileError.scala +++ /dev/null @@ -1 +0,0 @@ -@main def compileError = prin \ No newline at end of file diff --git a/compiler/test-resources/scripting/exit-code-tests/positiveTest.scala b/compiler/test-resources/scripting/exit-code-tests/positiveTest.scala deleted file mode 100644 index f3dbe50aa643..000000000000 --- a/compiler/test-resources/scripting/exit-code-tests/positiveTest.scala +++ /dev/null @@ -1 +0,0 @@ -@main def positiveTest = println("Hello World!") \ No newline at end of file diff --git a/compiler/test-resources/scripting/exit-code-tests/runtimeError.scala b/compiler/test-resources/scripting/exit-code-tests/runtimeError.scala deleted file mode 100644 index f6bdba466455..000000000000 --- a/compiler/test-resources/scripting/exit-code-tests/runtimeError.scala +++ /dev/null @@ -1 +0,0 @@ -@main def runtimeError = throw RuntimeException() diff --git a/compiler/test-resources/scripting/exit-code-tests/scriptCompileError.sc b/compiler/test-resources/scripting/exit-code-tests/scriptCompileError.sc deleted file mode 100644 index 36a59d06f3c4..000000000000 --- a/compiler/test-resources/scripting/exit-code-tests/scriptCompileError.sc +++ /dev/null @@ -1 +0,0 @@ -@main def main = prin \ No newline at end of file diff --git a/compiler/test-resources/scripting/exit-code-tests/scriptPositive.sc b/compiler/test-resources/scripting/exit-code-tests/scriptPositive.sc deleted file mode 100644 index a4dd0823f7a8..000000000000 --- a/compiler/test-resources/scripting/exit-code-tests/scriptPositive.sc +++ /dev/null @@ -1 +0,0 @@ -@main def scriptPositive = println("Hello world!") \ No newline at end of file diff --git a/compiler/test-resources/scripting/exit-code-tests/scriptRuntimeError.sc b/compiler/test-resources/scripting/exit-code-tests/scriptRuntimeError.sc deleted file mode 100644 index 0cd940cc20cf..000000000000 --- a/compiler/test-resources/scripting/exit-code-tests/scriptRuntimeError.sc +++ /dev/null @@ -1 +0,0 @@ -@main def scriptRuntimeError = throw RuntimeException() \ No newline at end of file diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index ebe0c007f7ec..f5a9559dffc9 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -4,187 +4,64 @@ package scripting import scala.language.unsafeNulls -import java.io.File -import java.nio.file.Files -import org.junit.Test +import java.nio.file.Files, java.nio.charset.StandardCharsets.UTF_8 +import org.junit.{ After, Test } import org.junit.Assert.assertEquals import org.junit.experimental.categories.Category import ScriptTestEnv.* - -object BashExitCodeTests: - private def testFiles = scripts("/scripting/exit-code-tests") - - /* - * Compiles the class checking exit code - * - * @param testName name of the test - * @param expectedExitCode expected exit code from the output - */ - private def compileAndVerifyExitCode( - testName: String, - expectedExitCode: Int, - )(using temporaryDir: File): Unit = - assertTestExists(testName) { testFile => - val testFilePath = testFile.absPath - val commandline = (Seq(scalacPath, "-d", temporaryDir.absPath, testFilePath)).mkString(" ") - val (validTest, exitCode, _, _) = bashCommand(commandline) - if verifyValid(validTest) then - assertEquals(expectedExitCode, exitCode) - } - - /* - * Runs compiled code checking the exit code - * - * @param className name of compiled class - * @param runExitCode expected exit code from the runner - */ - private def runClassAndVerifyExitCode( - className: String, - expectedExitCode: Int - )(using temporaryDir: File): Unit = - val testClassFile = temporaryDir.files.find(_.getName == s"$className.class") - assert(testClassFile.isDefined) - val commandline = (Seq(scalaPath, "-classpath", temporaryDir.absPath, className)).mkString(" ") - val (validTest, exitCode, _, _) = bashCommand(commandline) - if verifyValid(validTest) then - assertEquals(expectedExitCode, exitCode) - - /* - * Compiles and then runs code verifying runner status code - * - * @param testName name of the test - * @param className name of compiled class - * @param expectedRunExitCode expected exit code from the runner - */ - private def compileRunAndVerifyExitCode( - testName: String, - className: String, - expectedRunExitCode: Int, - )(using File): Unit = - compileAndVerifyExitCode(testName, 0) - runClassAndVerifyExitCode(className, expectedRunExitCode) - - /* - * Runs the command and checks the exit code - * - * @param args arguments for command line - * @param expectedExitCode expected exit code from the output - */ - private def testCommandExitCode(args: Seq[String], expectedExitCode: Int): Unit = - val commandline = args.mkString(" ") - val (validTest, exitCode, _, _) = bashCommand(commandline) - if verifyValid(validTest) then - assertEquals(expectedExitCode, exitCode) - - /* - * Checks if scripting test resources contains test with given `testName` - * And then runs function `test` - * - * @param testName name of the test containing the extension - * @param test check to be run on found test file - */ - private def assertTestExists(testName: String)(test: File => Unit) = - val file = testFiles.find(_.getName == testName) - assert(file.isDefined) - test(file.get) - - /* - * Runs test for created temporary file - * and ensures it deletion after function execution - * - * @param test check to be run on found test file - */ - private def withTempFile(test: File => Unit) = - val tempFile = Files.createTempFile("temp-file", ".class").toFile - try { - test(tempFile) - } finally { - Util.deleteFile(tempFile) - } - - /* - * Runs test with implicit temporary directory - * and ensures it deletion after the function execution - * - * @param test test to be run with given temporary directory - */ - private def withTempDirectory(test: File ?=> Unit) = - given file: File = Files.createTempDirectory("exit-code-tests").toFile - try { test } finally { Util.deleteFile(file) } - - /* - * Returns path to the generated tasty file for given directory and classname - */ - private def getGeneratedTastyPath(className: String)(using temporaryDir: File): String = - val file = temporaryDir.files.find(_.getName == s"$className.tasty") - assert(file.isDefined) - file.get.absPath - @Category(Array(classOf[BootstrappedOnlyTests])) class BashExitCodeTests: - import BashExitCodeTests.* - - @Test def verifyExitCodeOnCompileError: Unit = - withTempDirectory(compileAndVerifyExitCode("compileError.scala", 1)) - - @Test def verifyExitCodeOnRuntimeError: Unit = - withTempDirectory(compileRunAndVerifyExitCode("runtimeError.scala", "runtimeError", 1)) + private var myTmpDir: String | Null = null + private lazy val tmpDir = { myTmpDir = Files.createTempDirectory("exit-code-tests").toFile.absPath; myTmpDir } + @After def cleanup(): Unit = if myTmpDir != null then io.Directory(myTmpDir).deleteRecursively() - @Test def verifyExitCode: Unit = - withTempDirectory(compileRunAndVerifyExitCode("positiveTest.scala", "positiveTest", 0)) - - @Test def verifyExitCodeOnScriptError: Unit = - assertTestExists("scriptRuntimeError.sc"){ file => - testCommandExitCode(Seq(scalacPath, "-script", file.absPath), 1) - } - - @Test def verifyExitCodeOnScriptErrorCompiler: Unit = - assertTestExists("scriptRuntimeError.sc") { file => - testCommandExitCode(Seq(scalacPath, "-script", file.absPath), 1) - } - - @Test def verifyExitCodeOnScript: Unit = - assertTestExists("scriptPositive.sc") { file => - testCommandExitCode(Seq(scalaPath, file.absPath), 0) - } - - @Test def verifyExitCodeOnScriptCompiler: Unit = - assertTestExists("scriptPositive.sc") { file => - testCommandExitCode(Seq(scalacPath, "-script", file.absPath), 0) - } - - @Test def verifyExitCodeOnDecompilation: Unit = - withTempDirectory { - compileAndVerifyExitCode("positiveTest.scala", 0) - testCommandExitCode(Seq(scalacPath, "-decompile", getGeneratedTastyPath("positiveTest")), 0) - } - - @Test def verifyExitCodeOnPrintTasty: Unit = - withTempDirectory { - compileAndVerifyExitCode("positiveTest.scala", 0) - testCommandExitCode(Seq(scalacPath, "-print-tasty", getGeneratedTastyPath("positiveTest")), 0) - } - - @Test def verifyExitCodeOnDecompilationFailure: Unit = - withTempFile(file => testCommandExitCode(Seq(scalacPath, "-decompile", file.absPath), 1)) - testCommandExitCode(Seq(scalacPath, "-decompile", "non-existing-file.tasty"), 1) - - @Test def verifyExitCodeOnPrintTastyFailure: Unit = - withTempFile(file => testCommandExitCode(Seq(scalacPath, "-print-tasty", file.absPath), 1)) - testCommandExitCode(Seq(scalacPath, "-print-tasty", "non-existing-file.tasty"), 1) - - @Test def verifyExitCodeOnExpressionCompileError: Unit = - testCommandExitCode(Seq(scalaPath, "-e", "'prinln(10*10)'"), 1) - - @Test def verifyExitCodeOnExpressionRuntimeError: Unit = - testCommandExitCode(Seq(scalaPath, "-e", "'1/0'"), 1) - - @Test def verifyExitCodeOnExpression: Unit = - testCommandExitCode(Seq(scalaPath, "-e", "'println(10*10)'"), 0) - - @Test def verifyExitCodeOnInfo: Unit = - List("--help", "--version", "-Xplugin-list", "-Vphases").foreach { flag => - testCommandExitCode(Seq(scalaPath, flag), 0) - } + /** Verify the exit code of running `cmd args*`. */ + def verifyExit(cmd: String, args: String*)(expectedExitCode: Int): Unit = + val (validTest, exitCode, stdout, stderr) = bashCommand((cmd +: args).mkString(" ")) + if verifyValid(validTest) then + assertEquals({ + def pp(n: String, ss: Seq[String]) = if ss.isEmpty then "" else s"\nstd$n:${ss.map("\n " + _).mkString}" + s"expected $expectedExitCode but got $exitCode${pp("out", stdout)}${pp("err", stderr)}" + }, expectedExitCode, exitCode) + + // Helpers for running scala, scalac, and scalac without the the output directory ("raw") + def scala(args: String*) = verifyExit(scalaPath, args*) + def scalacRaw(args: String*) = verifyExit(scalacPath, args*) + def scalac(args: String*) = scalacRaw(("-d" +: tmpDir +: args)*) + + /** The path to the test file for this class. */ + def f(body: String, suffix: String = ".scala"): String = + Files.write(Files.createTempFile(tmpDir.toPath, getClass.getSimpleName, suffix), body.getBytes(UTF_8)).absPath + + @Test def neg = scalac(f("@main def Test = prin"))(1) + @Test def run = scalac(f("@main def Test = ???"))(0) & scala("-classpath", tmpDir, "Test")(1) + @Test def pos = scalac(f("@main def Test = ()"))(0) & scala("-classpath", tmpDir, "Test")(0) + + @Test def runNeg = scala(f("@main def Test = prin", ".sc"))(1) + @Test def runRun = scala(f("@main def Test = ???", ".sc"))(1) + @Test def runPos = scala(f("@main def Test = ()", ".sc"))(0) + + @Test def scNeg = scalac("-script", f("@main def Test = prin", ".sc"))(1) + @Test def scRun = scalac("-script", f("@main def Test = ???", ".sc"))(1) + @Test def scPos = scalac("-script", f("@main def Test = ()", ".sc"))(0) + + @Test def evalNeg = scala("-e", "'prinln(10*10)'")(1) + @Test def evalRun = scala("-e", "'1/0'")(1) + @Test def evalPos = scala("-e", "'println(10*10)'")(0) + + @Test def decompileNeg = scalac("-decompile", "non-existing-file.tasty")(1) + @Test def decompilePos = scalac(f("class Test"))(0) & scalacRaw("-decompile", s"$tmpDir/Test.tasty")(0) + + @Test def printTastyNeg = scalac("-print-tasty", "non-existing-file.tasty")(1) + @Test def printTastyPos = scalac(f("class Test"))(0) & scalacRaw("-print-tasty", s"$tmpDir/Test.tasty")(0) + + @Test def help = scala("--help")(0) + @Test def version = scala("--version")(0) + @Test def xPluginList = scala("-Xplugin-list")(0) + @Test def vPhases = scala("-Vphases")(0) + + /** A utility for running two commands in a row, like you do in bash. */ + extension (inline u1: Unit) inline def & (inline u2: Unit): Unit = { u1; u2 } +end BashExitCodeTests