Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ScriptEngine in ScalaTest

The following test should pass, but it doesn't

class EngineTest extends FunSuite {

  test("engine should not be null") {
    val manager: ScriptEngineManager = new ScriptEngineManager
    val engine: ScriptEngine = manager.getEngineByName("nashorn")
    assert(engine != null)
  }
}

The manager.getEngineFactories() seems to be empty. Why? How to init the context?

like image 458
jonbros Avatar asked May 09 '14 14:05

jonbros


2 Answers

You need to explicitly pass in a ClassLoader to the ScriptEngineManager constructor. If you don't then it uses Thread.currentThread().getContextClassLoader() which is set to something weird when running under SBT. We just pass in null in our code to get it to work. You can also pass in getClass.getClassLoader:

class EngineTest extends FunSuite {
  test("engine should not be null - null classloader") {
    val manager: ScriptEngineManager = new ScriptEngineManager(null)
    val engine: ScriptEngine = manager.getEngineByName("nashorn")
    assert(engine != null)
  }

  test("engine should not be null - getClass.getClassLoader classloader") {
    val manager: ScriptEngineManager = new ScriptEngineManager(getClass.getClassLoader)
    val engine: ScriptEngine = manager.getEngineByName("nashorn")
    assert(engine != null)
  }
}

Both of those tests pass for me:

[info] EngineTest:
[info] - engine should not be null - null classloader
[info] - engine should not be null - getClass.getClassLoader classloader
[info] Run completed in 186 milliseconds.
[info] Total number of tests run: 2
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
like image 185
tpunder Avatar answered Oct 26 '22 04:10

tpunder


What versions are you using? This is sbt .13.

> console
[info] Starting scala interpreter...
[info] 
Welcome to Scala version 2.11.0 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import javax.script._
import javax.script._

scala> new ScriptEngineManager().getEngineByName("scala")
res0: javax.script.ScriptEngine = scala.tools.nsc.interpreter.IMain@7078c799

scala> new ScriptEngineManager().getEngineByName("rhino")
res1: javax.script.ScriptEngine = com.sun.script.javascript.RhinoScriptEngine@5c854934

scala> new ScriptEngineManager().getEngineFactories
res2: java.util.List[javax.script.ScriptEngineFactory] = [com.sun.script.javascript.RhinoScriptEngineFactory@454ee4c0, scala.tools.nsc.interpreter.IMain$Factory@354e3bce]

Wait, you asked about test context --

Well, before I lost interest in decoding more sbt, adding to libraryDependencies:

"org.scala-lang" % "scala-compiler" % scalaVersion.value % "test",

enables locating the Scala script engine:

  @Test def engines: Unit = {
    import javax.script._
    val all = new ScriptEngineManager().getEngineFactories
    Console println s"Found ${all.size}: $all"
    assert(all.size > 0)
  }

No doubt there's a simple way to add runtime:full-classpath to test:full-classpath directly. Because it's the simple build tool, right?

For Nashorn on Java 8, note the location:

> set fullClasspath in Test += Attributed.blank(file(s"${util.Properties.javaHome}/lib/ext/nashorn.jar"))
[info] Defining test:fullClasspath
[info] The new value will be used by test:console, test:executeTests and 5 others.
[info]  Run `last` for details.
[info] Reapplying settings...
[info] Set current project to goofy (in build file:/home/apm/goofy/)
> test
Found 1: [jdk.nashorn.api.scripting.NashornScriptEngineFactory@7fa2239d]
[info] Passed: Total 10, Failed 0, Errors 0, Passed 10

Update: https://github.com/sbt/sbt/issues/1214

Also I guess it's still considered black art:

// Somehow required to get a js engine in tests (https://github.com/sbt/sbt/issues/1214)

fork in Test := true
like image 3
som-snytt Avatar answered Oct 26 '22 05:10

som-snytt