How to set an expected exception using Scala and JUnit 4 - scala

I want to set an expected exception for a JUnit 4 test using Scala. I am current doing something similar to the following:
#Test(expected=classOf[NullPointerException])
def someTest() = {
// Some test code
}
But I get the following compiler error:
error: wrong number of arguments for constructor Test: ()org.junit.Test

This is looking forward a bit, but the syntax for annotations in 2.8 has changed to be the same as what you originally posted. The syntax Tristan posted is correct in the current stable version, but it gave me errors when I upgraded my project to a nightly 2.8 compiler. I'm guessing this is due to the inclusion of named and default arguments. There is also some discussion on the Scala mailing list. Quoting Lukas Rytz:
Also note that in 2.8.0 the syntax for java annotations will no longer use the name-value
pairs but named arguments instead, i.e.
#ann{ val x = 1, val y = 2} ==> #ann(x = 1, y = 2)

The way scala deals with attributes is a little funky. I think what you're trying to do should be expressed like this:
#Test { val expected = classOf[ NullPointerException] }
def someTest {
// test code
}
Scala language page with many annotation examples.

This works for me (JUnit 4.10, Scala 2.10.2):
#Test(expected = classOf[NullPointerException])
def testFoo() {
foo(null)
}
Similar to what Tristan suggested, but this syntax actually compiles and works in my project.
Edit: Uh, looking closer, this is exactly what the original question had. Well, I guess having the latest working syntax also in answers doesn't hurt.

You can also try specs with:
class mySpec extends SpecificationWithJUnit {
"this expects an exception" in {
myCode must throwA[NullPointerException]
}
}
Eric.

Use ScalaTest and JUnit together and you can do:
import org.scalatest.junit.JUnitSuite
import org.scalatest.junit.ShouldMatchersForJUnit
import org.junit.Test
class ExampleSuite extends JUnitSuite with ShouldMatchersForJUnit {
#Test def toTest() {
evaluating { "yo".charAt(-1) } should produce [StringIndexOutOfBoundsException]
}
}

Related

Using Scala Toolbox eval, how do I define I value I can use in later evals?

I'm using Scala toolbox to eval some Scala code for a web interpreter. It is working well, the code looks like this:
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
object Eval {
val toolbox = runtimeMirror(getClass.getClassLoader).mkToolBox()
def eval[T](code: String): T = {
toolbox.eval(toolbox.parse(code)).asInstanceOf[T]
}
}
I can do something like:
Eval.eval[Long]("1 + 1")
and get 2 back. The question comes up when I want to define something:
Eval.eval[Unit]("val yellow = 5")
Eval.eval[Long]("yellow")
I get a not found: value yellow error. How do I define a value that I can use in later evaluations with Scala Toolbox?
For a persistent environment, you can use Scala's REPL directly. See the JSR-223 note at the very bottom of the 2.11 release notes.
import javax.script.ScriptEngineManager
class DummyClass
object Evaluator {
val engine = new ScriptEngineManager().getEngineByName("scala")
val settings = engine.asInstanceOf[scala.tools.nsc.interpreter.IMain].settings
settings.embeddedDefaults[DummyClass]
engine.eval("val x: Int = 5")
val thing = engine.eval("x + 9").asInstanceOf[Int]
}
The need for DummyClass (or really any class you have can substitute for DummyClass) arises from a bit of shenanigans going on here due to SBT and classloader concerns (more details here).

How to compile/eval a Scala expression at runtime?

New to Scala and looking for pointers to an idiomatic solution, if there is one.
I'd like to have arbitrary user-supplied Scala functions (which are allowed to reference functions/classes I have defined in my code) applied to some data.
For example: I have foo(s: String): String and bar(s: String): String functions defined in my myprog.scala. The user runs my program like this:
$ scala myprog data.txt --func='(s: Str) => foo(bar(s)).reverse'
This would run line by line through the data file and emit the result of applying the user-specified function to that line.
For extra points, can I ensure that there are no side-effects in the user-defined function? If not, can I restrict the function to use only a restricted subset of functions (which I can assure to be safe)?
#kenjiyoshida has a nice gist that shows how to eval Scala code. Note that when using Eval from that gist, not specifying a return value will result in a runtime failure when Scala defaults to inferring Nothing.
scala> Eval("println(\"Hello\")")
Hello
java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to scala.runtime.Nothing$
... 42 elided
vs
scala> Eval[Unit]("println(\"Hello\")")
Hello
It nicely handles whatever's in scope as well.
object Thing {
val thing: Int = 5
}
object Eval {
def apply[A](string: String): A = {
val toolbox = currentMirror.mkToolBox()
val tree = toolbox.parse(string)
toolbox.eval(tree).asInstanceOf[A]
}
def fromFile[A](file: File): A =
apply(scala.io.Source.fromFile(file).mkString(""))
def fromFileName[A](file: String): A =
fromFile(new File(file))
}
object Thing2 {
val thing2 = Eval[Int]("Thing.thing") // 5
}
Twitter's util package used to have util-eval, but that seems to have been deprecated now (and also triggers a compiler bug when compiled).
As for the second part of your question, the answer seems to be no. Even if you disable default Predef and imports yourself, a user can always get to those functions with the fully qualified package name. You could perhaps use Scala's scala.tools.reflect.ToolBox to first parse your string and then compare against a whitelist, before passing to eval, but at that point things could get pretty hairy since you'll be manually writing code to sanitize the Scala AST (or at the very least reject dangerous input). It definitely doesn't seem to be an "idiomatic solution."
This should be possible by using the standard Java JSR 223 Scripting Engine
see https://issues.scala-lang.org/browse/SI-874
(also mentions using scala.tools.nsc.Interpreter but not sure this is still available)
import javax.script.*;
ScriptEngine e = new ScriptEngineManager().getEngineByName("scala");
e.getContext().setAttribute("label", new Integer(4), ScriptContext.ENGINE_SCOPE);
try {
engine.eval("println(2+label)");
} catch (ScriptException ex) {
ex.printStackTrace();
}

"Input mismatch: Tuple type expected" when trying to select on PatternStream

I’m having a bit of trouble testing the new Flink 1.0.0 functionalities. I’ve been tinkering around with CEP and I didn’t yet managed to run a simple demo code:
val pattern : Pattern[TrafficEvent, _] = Pattern.begin[TrafficEvent]("start")
val patternStream = CEP.pattern(stream.javaStream, pattern);
class MyPatternSelectFunction extends PatternSelectFunction[TrafficEvent, TrafficEvent] {
override def select(pattern : java.util.Map[String, TrafficEvent]) : TrafficEvent ={
pattern.get("start")
}
}
val alerts = patternStream.select(new MyPatternSelectFunction())
The code compiles well, and maven show no warnings. TrafficEvent is a class with few simple fields, and stream is a Scala DataStream of that class. The error shows up when the code is running on Flink. It runs for a second, and then the code exits with this error message:
The program finished with the following exception:
Input mismatch: Tuple type expected.
org.apache.flink.api.java.typeutils.TypeExtractor.validateInputType(TypeExtractor.java:878)
org.apache.flink.api.java.typeutils.TypeExtractor.getUnaryOperatorReturnType(TypeExtractor.java:302)
org.apache.flink.cep.PatternStream.select(PatternStream.java:64)
com.demo.DemoTraffic$.main(DemoTraffic.scala:311)
I’ve tried to move the functionality to Java, by building a static class like this (Maybe there are some weird issues calling the API from Scala):
public static DataStream<DemoTraffic.trafficEvent> getStreamByPattern(DataStream<DemoTraffic.trafficEvent> stream) {
Pattern<DemoTraffic.trafficEvent, ?> pattern = Pattern.<DemoTraffic.trafficEvent>begin("start");
PatternStream<DemoTraffic.trafficEvent> patternStream = CEP.pattern(stream, pattern);
DataStream<DemoTraffic.trafficEvent> rvalue = patternStream.select(new PatternSelectFunction<DemoTraffic.trafficEvent, DemoTraffic.trafficEvent>() {
#Override
public DemoTraffic.trafficEvent select(Map<String, DemoTraffic.trafficEvent> pattern) throws Exception {
return pattern.get("start");
}
});
return rvalue;
}
But the result is exactly the same, and it throws the same error in the PatternStream.select line. Any hints about what can I try or what I’m doing wrong? As you can see, the pattern is pretty stupid, and it's only for testing purpouses. It only accepts all events, and gives back that event in response. Flink is 1.0.0, using Scala 2.10 version.
Thanks
I assume that TrafficEvent is a Scala case class. The CEP library has been written for Flink's Java API and, thus, does not support Scala case classes, yet.
As a workaround, you could translate your case class into a normal Scala class.
There is also a JIRA ticket which tracks the development of the CEP Scala API.

Diagnosing Scala compile error "value to is not a member of Int"

I made a code change within a Scala class that had been working fine. Upon trying to compile the modification, the compiler spit out the error message, "value to is not a member of Int" relating to this (pre-existing) line of code:
for (i <- 0 to cColumn -1) { ... }
Doing some research, I came across some bug reports on the "to" method - and also that "to" is apparently a method provided within the intWrapper class(?).
So, based upon that info, I started looking at my class's import statements... no such import for intWrapper. (Q: That being the case, how did this ever compile/run in the first place?) What makes this even more interesting (to me) is that when I started to do a global search in the codebase for that import I accidentally terminated the compiler (sbt) session...but when I restarted it, the class compiled just fine. No errors at all. (And no code changes from the previous session)
Anyone have any ideas as to what would cause this intermittent behavior?
NOTES:
1) using Scala 2.10.2 with javac 1.7.0_25
2) the code change to the class had nothing to do with the example functionality, nor did it alter any of the class's imports
Update: Here are the variable declarations:
val meta = rs.getMetaData()
val cColumn = meta.getColumnCount()
EDIT: Per suggestion, here is the test lines (all of them compile fine now):
implicitly[scala.Int => scala.runtime.RichInt]
intWrapper(3) to 4
for (i <- 0 to 33 -1) { /* do something smart */ }
for (i <- 0 to cColumn -1) { ... }
EDIT 2 Here is the full compiler error:
[error] /path/to/src/file/DBO.scala:329: value to is not a member of Int
[error] for (i <- 0 to cColumn -1) {
[error]
That error was repeating ~18 times in the class. (It's a DBO-DB interface layer); where DBO.scala is the file containing the newly modified trait.
I just encountered this same issue. In my case, it was caused by an unnecessary import, like this:
import scala.Predef.String
class Test() {
for (t <- 1 to 3) {}
}
By default, Scala imports all of scala.Predef. Predef extends LowPriorityImplicits, which includes an implicit conversion from Int to RichInt.
to is actually defined on RichInt, so you need this conversion in order to use it. By importing just part of Predef, I lose this conversion. Get rid of the unnecessary import and the error goes away.
how did this ever compile/run in the first place?
By default, the contents of scala.Predef is imported. There you have method intWrapper which produces a RichInt with method to.
You probably have shadowed symbol intWrapper. Does the following work:
implicitly[scala.Int => scala.runtime.RichInt]
or this:
intWrapper(3) to 4
...if not, there lies your problem.
EDIT: So, since you say that compiles, what happens is you replace cColumn with a constant, e.g.
for (i <- 0 to 33 -1) { ... }
? It would also help to post the complete compiler message with indicated line etc.
Without knowing where that error comes from, you might also try to work around it by constructing the Range by hand:
for (i <- Range.inclusive(0, cColumn-1)) { ... }
or
Range.inclusive(0, cColumn-1).foreach { i => ... }

Is it possible to use scalap from a scala script?

I am using scalap to read out the field names of some case classes (as discussed in this question). Both the case classes and the code that uses scalap to analyze them have been compiled and put into a jar file on the classpath.
Now I want to run a script that uses this code, so I followed the instructions and came up with something like
::#!
#echo off
call scala -classpath *;./libs/* %0 %*
goto :eof
::!#
//Code relying on pre-compiled code that uses scalap
which does not work:
java.lang.ClassCastException: scala.None$ cannot be cast to scala.Option
at scala.tools.nsc.interpreter.ByteCode$.caseParamNamesForPath(ByteCode.
scala:45)
at scala.tools.nsc.interpreter.ProductCompletion.caseNames(ProductComple
tion.scala:22)
However, the code works just fine when I compile everything. I played around with additional scala options like -savecompiled, but this did not help. Is this a bug, or can't this work in principle? (If so, could someone explain why not? As I said, the case classes that shall be analyzed by scalap are compiled.)
Note: I use Scala 2.9.1-1.
EDIT
Here is what I am essentially trying to do (providing a simple way to create multiple instances of a case class):
//This is pre-compiled:
import scala.tools.nsc.interpreter.ProductCompletion
//...
trait MyFactoryTrait[T <: MyFactoryTrait[T] with Product] {
this: T =>
private[this] val copyMethod = this.getClass.getMethods.find(x => x.getName == "copy").get
lazy val productCompletion = new ProductCompletion(this)
/** The names of all specified fields. */
lazy val fieldNames = productCompletion.caseNames //<- provokes the exception (see above)
def createSeq(...):Seq[T] = {
val x = fieldNames map { ... } // <- this method uses the fieldNames value
//[...] invoke copyMethod to create instances
}
// ...
}
//This is pre-compiled too:
case class MyCaseClass(x: Int = 0, y: Int = 0) extends MyFactoryTrait[MyCaseClass]
//This should be interpreted (but crashes):
val seq = MyCaseClass().createSeq(...)
Note: I moved on to Scala 2.9.2, the error stays the same (so probably not a bug).
This is a bug in the compiler:
If you run the program inside an ide, for example Intellij IDEA the code is executed fine, however no fields names are found.
If you run it from command line using scala, you obtain the error you mentioned.
There is no way type-safe could should ever compiler and throw a runtime ClassCastException.
Please open a bug at https://issues.scala-lang.org/secure/Dashboard.jspa