@@ -4,187 +4,64 @@ package scripting
44
55import scala .language .unsafeNulls
66
7- import java .io .File
8- import java .nio .file .Files
9- import org .junit .Test
7+ import java .nio .file .Files , java .nio .charset .StandardCharsets .UTF_8
8+ import org .junit .{ After , Test }
109import org .junit .Assert .assertEquals
1110import org .junit .experimental .categories .Category
1211
1312import ScriptTestEnv .*
1413
15-
16- object BashExitCodeTests :
17- private def testFiles = scripts(" /scripting/exit-code-tests" )
18-
19- /*
20- * Compiles the class checking exit code
21- *
22- * @param testName name of the test
23- * @param expectedExitCode expected exit code from the output
24- */
25- private def compileAndVerifyExitCode (
26- testName : String ,
27- expectedExitCode : Int ,
28- )(using temporaryDir : File ): Unit =
29- assertTestExists(testName) { testFile =>
30- val testFilePath = testFile.absPath
31- val commandline = (Seq (scalacPath, " -d" , temporaryDir.absPath, testFilePath)).mkString(" " )
32- val (validTest, exitCode, _, _) = bashCommand(commandline)
33- if verifyValid(validTest) then
34- assertEquals(expectedExitCode, exitCode)
35- }
36-
37- /*
38- * Runs compiled code checking the exit code
39- *
40- * @param className name of compiled class
41- * @param runExitCode expected exit code from the runner
42- */
43- private def runClassAndVerifyExitCode (
44- className : String ,
45- expectedExitCode : Int
46- )(using temporaryDir : File ): Unit =
47- val testClassFile = temporaryDir.files.find(_.getName == s " $className.class " )
48- assert(testClassFile.isDefined)
49- val commandline = (Seq (scalaPath, " -classpath" , temporaryDir.absPath, className)).mkString(" " )
50- val (validTest, exitCode, _, _) = bashCommand(commandline)
51- if verifyValid(validTest) then
52- assertEquals(expectedExitCode, exitCode)
53-
54- /*
55- * Compiles and then runs code verifying runner status code
56- *
57- * @param testName name of the test
58- * @param className name of compiled class
59- * @param expectedRunExitCode expected exit code from the runner
60- */
61- private def compileRunAndVerifyExitCode (
62- testName : String ,
63- className : String ,
64- expectedRunExitCode : Int ,
65- )(using File ): Unit =
66- compileAndVerifyExitCode(testName, 0 )
67- runClassAndVerifyExitCode(className, expectedRunExitCode)
68-
69- /*
70- * Runs the command and checks the exit code
71- *
72- * @param args arguments for command line
73- * @param expectedExitCode expected exit code from the output
74- */
75- private def testCommandExitCode (args : Seq [String ], expectedExitCode : Int ): Unit =
76- val commandline = args.mkString(" " )
77- val (validTest, exitCode, _, _) = bashCommand(commandline)
78- if verifyValid(validTest) then
79- assertEquals(expectedExitCode, exitCode)
80-
81- /*
82- * Checks if scripting test resources contains test with given `testName`
83- * And then runs function `test`
84- *
85- * @param testName name of the test containing the extension
86- * @param test check to be run on found test file
87- */
88- private def assertTestExists (testName : String )(test : File => Unit ) =
89- val file = testFiles.find(_.getName == testName)
90- assert(file.isDefined)
91- test(file.get)
92-
93- /*
94- * Runs test for created temporary file
95- * and ensures it deletion after function execution
96- *
97- * @param test check to be run on found test file
98- */
99- private def withTempFile (test : File => Unit ) =
100- val tempFile = Files .createTempFile(" temp-file" , " .class" ).toFile
101- try {
102- test(tempFile)
103- } finally {
104- Util .deleteFile(tempFile)
105- }
106-
107- /*
108- * Runs test with implicit temporary directory
109- * and ensures it deletion after the function execution
110- *
111- * @param test test to be run with given temporary directory
112- */
113- private def withTempDirectory (test : File ?=> Unit ) =
114- given file : File = Files .createTempDirectory(" exit-code-tests" ).toFile
115- try { test } finally { Util .deleteFile(file) }
116-
117- /*
118- * Returns path to the generated tasty file for given directory and classname
119- */
120- private def getGeneratedTastyPath (className : String )(using temporaryDir : File ): String =
121- val file = temporaryDir.files.find(_.getName == s " $className.tasty " )
122- assert(file.isDefined)
123- file.get.absPath
124-
12514@ Category (Array (classOf [BootstrappedOnlyTests ]))
12615class BashExitCodeTests :
127- import BashExitCodeTests .*
128-
129- @ Test def verifyExitCodeOnCompileError : Unit =
130- withTempDirectory(compileAndVerifyExitCode(" compileError.scala" , 1 ))
131-
132- @ Test def verifyExitCodeOnRuntimeError : Unit =
133- withTempDirectory(compileRunAndVerifyExitCode(" runtimeError.scala" , " runtimeError" , 1 ))
16+ private var myTmpDir : String | Null = null
17+ private lazy val tmpDir = { myTmpDir = Files .createTempDirectory(" exit-code-tests" ).toFile.absPath; myTmpDir }
18+ @ After def cleanup (): Unit = if myTmpDir != null then io.Directory (myTmpDir).deleteRecursively()
13419
135- @ Test def verifyExitCode : Unit =
136- withTempDirectory(compileRunAndVerifyExitCode(" positiveTest.scala" , " positiveTest" , 0 ))
137-
138- @ Test def verifyExitCodeOnScriptError : Unit =
139- assertTestExists(" scriptRuntimeError.sc" ){ file =>
140- testCommandExitCode(Seq (scalacPath, " -script" , file.absPath), 1 )
141- }
142-
143- @ Test def verifyExitCodeOnScriptErrorCompiler : Unit =
144- assertTestExists(" scriptRuntimeError.sc" ) { file =>
145- testCommandExitCode(Seq (scalacPath, " -script" , file.absPath), 1 )
146- }
147-
148- @ Test def verifyExitCodeOnScript : Unit =
149- assertTestExists(" scriptPositive.sc" ) { file =>
150- testCommandExitCode(Seq (scalaPath, file.absPath), 0 )
151- }
152-
153- @ Test def verifyExitCodeOnScriptCompiler : Unit =
154- assertTestExists(" scriptPositive.sc" ) { file =>
155- testCommandExitCode(Seq (scalacPath, " -script" , file.absPath), 0 )
156- }
157-
158- @ Test def verifyExitCodeOnDecompilation : Unit =
159- withTempDirectory {
160- compileAndVerifyExitCode(" positiveTest.scala" , 0 )
161- testCommandExitCode(Seq (scalacPath, " -decompile" , getGeneratedTastyPath(" positiveTest" )), 0 )
162- }
163-
164- @ Test def verifyExitCodeOnPrintTasty : Unit =
165- withTempDirectory {
166- compileAndVerifyExitCode(" positiveTest.scala" , 0 )
167- testCommandExitCode(Seq (scalacPath, " -print-tasty" , getGeneratedTastyPath(" positiveTest" )), 0 )
168- }
169-
170- @ Test def verifyExitCodeOnDecompilationFailure : Unit =
171- withTempFile(file => testCommandExitCode(Seq (scalacPath, " -decompile" , file.absPath), 1 ))
172- testCommandExitCode(Seq (scalacPath, " -decompile" , " non-existing-file.tasty" ), 1 )
173-
174- @ Test def verifyExitCodeOnPrintTastyFailure : Unit =
175- withTempFile(file => testCommandExitCode(Seq (scalacPath, " -print-tasty" , file.absPath), 1 ))
176- testCommandExitCode(Seq (scalacPath, " -print-tasty" , " non-existing-file.tasty" ), 1 )
177-
178- @ Test def verifyExitCodeOnExpressionCompileError : Unit =
179- testCommandExitCode(Seq (scalaPath, " -e" , " 'prinln(10*10)'" ), 1 )
180-
181- @ Test def verifyExitCodeOnExpressionRuntimeError : Unit =
182- testCommandExitCode(Seq (scalaPath, " -e" , " '1/0'" ), 1 )
183-
184- @ Test def verifyExitCodeOnExpression : Unit =
185- testCommandExitCode(Seq (scalaPath, " -e" , " 'println(10*10)'" ), 0 )
186-
187- @ Test def verifyExitCodeOnInfo : Unit =
188- List (" --help" , " --version" , " -Xplugin-list" , " -Vphases" ).foreach { flag =>
189- testCommandExitCode(Seq (scalaPath, flag), 0 )
190- }
20+ /** Verify the exit code of running `cmd args*`. */
21+ def verifyExit (cmd : String , args : String * )(expectedExitCode : Int ): Unit =
22+ val (validTest, exitCode, stdout, stderr) = bashCommand((cmd +: args).mkString(" " ))
23+ if verifyValid(validTest) then
24+ assertEquals({
25+ def pp (n : String , ss : Seq [String ]) = if ss.isEmpty then " " else s " \n std $n: ${ss.map(" \n " + _).mkString}"
26+ s " expected $expectedExitCode but got $exitCode${pp(" out" , stdout)}${pp(" err" , stderr)}"
27+ }, expectedExitCode, exitCode)
28+
29+ // Helpers for running scala, scalac, and scalac without the the output directory ("raw")
30+ def scala (args : String * ) = verifyExit(scalaPath, args* )
31+ def scalacRaw (args : String * ) = verifyExit(scalacPath, args* )
32+ def scalac (args : String * ) = scalacRaw((" -d" +: tmpDir +: args)* )
33+
34+ /** The path to the test file for this class. */
35+ def f (body : String , suffix : String = " .scala" ): String =
36+ Files .write(Files .createTempFile(tmpDir.toPath, getClass.getSimpleName, suffix), body.getBytes(UTF_8 )).absPath
37+
38+ @ Test def neg = scalac(f(" @main def Test = prin" ))(1 )
39+ @ Test def run = scalac(f(" @main def Test = ???" ))(0 ) & scala(" -classpath" , tmpDir, " Test" )(1 )
40+ @ Test def pos = scalac(f(" @main def Test = ()" ))(0 ) & scala(" -classpath" , tmpDir, " Test" )(0 )
41+
42+ @ Test def runNeg = scala(f(" @main def Test = prin" , " .sc" ))(1 )
43+ @ Test def runRun = scala(f(" @main def Test = ???" , " .sc" ))(1 )
44+ @ Test def runPos = scala(f(" @main def Test = ()" , " .sc" ))(0 )
45+
46+ @ Test def scNeg = scalac(" -script" , f(" @main def Test = prin" , " .sc" ))(1 )
47+ @ Test def scRun = scalac(" -script" , f(" @main def Test = ???" , " .sc" ))(1 )
48+ @ Test def scPos = scalac(" -script" , f(" @main def Test = ()" , " .sc" ))(0 )
49+
50+ @ Test def evalNeg = scala(" -e" , " 'prinln(10*10)'" )(1 )
51+ @ Test def evalRun = scala(" -e" , " '1/0'" )(1 )
52+ @ Test def evalPos = scala(" -e" , " 'println(10*10)'" )(0 )
53+
54+ @ Test def decompileNeg = scalac(" -decompile" , " non-existing-file.tasty" )(1 )
55+ @ Test def decompilePos = scalac(f(" class Test" ))(0 ) & scalacRaw(" -decompile" , s " $tmpDir/Test.tasty " )(0 )
56+
57+ @ Test def printTastyNeg = scalac(" -print-tasty" , " non-existing-file.tasty" )(1 )
58+ @ Test def printTastyPos = scalac(f(" class Test" ))(0 ) & scalacRaw(" -print-tasty" , s " $tmpDir/Test.tasty " )(0 )
59+
60+ @ Test def help = scala(" --help" )(0 )
61+ @ Test def version = scala(" --version" )(0 )
62+ @ Test def xPluginList = scala(" -Xplugin-list" )(0 )
63+ @ Test def vPhases = scala(" -Vphases" )(0 )
64+
65+ /** A utility for running two commands in a row, like you do in bash. */
66+ extension (inline u1 : Unit ) inline def & (inline u2 : Unit ): Unit = { u1; u2 }
67+ end BashExitCodeTests
0 commit comments