Skip to content

test added to BashScriptsTests to verify script.path property #13132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified compiler/test-resources/scripting/hashBang.sc
100644 → 100755
Empty file.
Empty file modified compiler/test-resources/scripting/mainClassOnStack.sc
100644 → 100755
Empty file.
Empty file modified compiler/test-resources/scripting/scriptPath.sc
100644 → 100755
Empty file.
82 changes: 70 additions & 12 deletions compiler/test/dotty/tools/scripting/BashScriptsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ import org.junit.Test
import vulpix.TestConfiguration


/** Runs all tests contained in `compiler/test-resources/scripting/` */
/** Verifies correct handling of command line arguments by `dist/bin/scala` and `dist/bin/scalac`.
* +. arguments following a script path must be treated as script arguments
* +. preserve script command line arguments.
*/
class BashScriptsTests:
// classpath tests managed by scripting.ClasspathTests.scala
def testFiles = scripts("/scripting").filter { ! _.getName.startsWith("classpath") }
def testFiles = scripts("/scripting")

lazy val expectedOutput = List(
"arg 0:[a]",
Expand All @@ -28,10 +31,10 @@ class BashScriptsTests:
lazy val testScriptArgs = Seq(
"a", "b", "c", "-repl", "-run", "-script", "-debug"
)
lazy val (bashExe,bashPath) =
lazy val (bashExe, bashPath) =
val bexe = getBashPath
val bpath = Paths.get(bexe)
printf("bashExe: [%s]\n", bexe)
// printf("bashExe: [%s]\n", bexe)
(bexe, bpath)

val showArgsScript = testFiles.find(_.getName == "showArgs.sc").get.absPath
Expand All @@ -41,13 +44,11 @@ class BashScriptsTests:

/* verify `dist/bin/scalac` */
@Test def verifyScalacArgs =
printf("scalacPath[%s]\n",scalacPath)
printf("scalacPath[%s]\n", scalacPath)
val commandline = (Seq(scalacPath, "-script", showArgsScript) ++ testScriptArgs).mkString(" ")
if bashPath.toFile.exists then
var cmd = Array(bashExe, "-c", commandline)
val output = for {
line <- Process(cmd).lazyLines_!
} yield line
val output = Process(cmd).lazyLines_!
var fail = false
printf("\n")
for (line, expect) <- output zip expectedOutput do
Expand All @@ -68,7 +69,7 @@ class BashScriptsTests:
} yield line
var fail = false
printf("\n")
var mismatches = List.empty[(String,String)]
var mismatches = List.empty[(String, String)]
for (line, expect) <- output zip expectedOutput do
printf("expected: %-17s\nactual : %s\n", expect, line)
if line != expect then
Expand All @@ -77,24 +78,81 @@ class BashScriptsTests:
if fail then
assert(output == expectedOutput)

extension (str: String) def dropExtension =
/*
* verify that scriptPath.sc sees a valid script.path property.
*/
@Test def verifyScriptPathProperty =
val scriptFile = testFiles.find(_.getName == "scriptPath.sc").get
val expected = s"/${scriptFile.getName}"
printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName)
val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath)
if exitCode == 0 && ! stderr.exists(_.contains("Permission denied")) then
// var cmd = Array(bashExe, "-c", scriptFile.absPath)
// val stdout = Process(cmd).lazyLines_!
stdout.foreach { printf("######### [%s]\n", _) }
val valid = stdout.exists { _.endsWith(expected) }
if valid then printf("# valid script.path reported by [%s]\n", scriptFile.getName)
assert(valid, s"script ${scriptFile.absPath} did not report valid script.path value")

/*
* verify SCALA_OPTS can specify an @argsfile when launching a scala script in `dist/bin/scala`.
*/
@Test def verifyScalaOpts =
val scriptFile = testFiles.find(_.getName == "classpathReport.sc").get
printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName)
val argsfile = createArgsFile() // avoid problems caused by drive letter
val envPairs = List(("SCALA_OPTS", s"@$argsfile"))
val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs:_*)
if exitCode != 0 || stderr.exists(_.contains("Permission denied")) then
stderr.foreach { System.err.printf("stderr [%s]\n", _) }
printf("unable to execute script, return value is %d\n", exitCode)
else
// val stdout: Seq[String] = Process(cmd, cwd, envPairs:_*).lazyLines_!.toList
val expected = s"${cwd.toString}"
val List(line1: String, line2: String) = stdout.take(2)
val valid = line2.dropWhile( _ != ' ').trim.startsWith(expected)
if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", cwd, scriptFile.getName)
assert(valid, s"script ${scriptFile.absPath} did not report valid java.class.path first entry")

lazy val cwd = Paths.get(dotty.tools.dotc.config.Properties.userDir).toFile

def createArgsFile(): String =
val utfCharset = java.nio.charset.StandardCharsets.UTF_8.name
val text = s"-classpath ${cwd.absPath}"
val path = Files.createTempFile("scriptingTest", ".args")
Files.write(path, text.getBytes(utfCharset))
path.toFile.getAbsolutePath.replace('\\', '/')

extension (str: String) def dropExtension: String =
str.reverse.dropWhile(_ != '.').drop(1).reverse

extension(f: File) def absPath =
extension(f: File) def absPath: String =
f.getAbsolutePath.replace('\\', '/')

lazy val osname = Option(sys.props("os.name")).getOrElse("").toLowerCase

def getBashPath: String =
var whichBash = ""
printf("osname[%s]\n", osname)
//printf("osname[%s]\n", osname)
if osname.startsWith("windows") then
whichBash = which("bash.exe")
else
whichBash = which("bash")

whichBash

def bashCommand(cmdstr: String, envPairs: (String, String)*): (Int, Seq[String], Seq[String]) = {
import scala.sys.process._
val cmd = Seq(bashExe, "-c", cmdstr)
val proc = Process(cmd, None, envPairs *)
var (stdout, stderr) = (List.empty[String], List.empty[String])
val exitVal = proc ! ProcessLogger (
(out: String) => stdout ::= out,
(err: String) => stderr ::= err
)
(exitVal, stdout.reverse, stderr.reverse)
}

def execCmd(command: String, options: String *): Seq[String] =
val cmd = (command :: options.toList).toSeq
for {
Expand Down
3 changes: 1 addition & 2 deletions compiler/test/dotty/tools/scripting/ClasspathTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ class ClasspathTests:
printf("bash is [%s]\n", bashExe)

if packBinScalaExists then
val echoTest = "" // "SCALAC_ECHO_TEST=1"
val bashCmdline = s"SCALA_OPTS= $echoTest ${scalaCopy.norm} -classpath '$wildcardEntry' $relpath"
val bashCmdline = s"SCALA_OPTS= ${scalaCopy.norm} -classpath '$wildcardEntry' $relpath"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why scala script path is part of SCALA_OPTS?

Copy link
Contributor Author

@philwalk philwalk Jul 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of prefixing the bash command line with SCALA_OPTS= is to unset SCALA_OPTS, to insure that it doesn't influence the command line args seen by dist/bin/scala. (there's a space following the equal sign, effectively unsetting SCALA_OPTS)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, I was curious about the blank space too, but now it makes sense


// ask [dist/bin/scalac] to echo generated command line so we can verify some things
val cmd = Array(bashExe, "-c", bashCmdline)
Expand Down