Specify TestNG test groups in Scala - scala

I'm trying to assign groups to TestNG classes and methods in a Scala environment (in Eclipse)
#Test(groups="register")
class RegisterTest {
...
but am encountering the following error:
Multiple markers at this line
- type mismatch; found : java.lang.String("register") required:
Array[java.lang.String]
- annotation argument needs to be a constant; found: "register"{<error>}
I've tried applying groups to individual Scala methods but still encounter the same error.
Any suggestions on how to get around this?
The#Testannotation works as long as it doesn't specify any parameters (same error if dependsOnMethodsparameter is specified).
#DataProviderannotation also works.

The ScalaDoc gives the following example:
#Test(groups = Array("com.mycompany.groups.SlowTest"))
def funTest() {
sb.append("fun!")
assert(sb.toString === "ScalaTest is fun!")
assert(lb.isEmpty)
}
That seems to match the error you get.

Related

can`t bind[SttpBackend[Try, Nothing]]

I want to use sttp library with guice(with scalaguice wrapper) in my app. But seems it is not so easy to correctly bind things like SttpBackend[Try, Nothing]
SttpBackend.scala
Try[_] and Try[AnyRef] show some other errors, but still have no idea how it should be done correctly
the error I got:
kinds of the type arguments (scala.util.Try) do not conform to the expected kinds of the type parameters (type T).
[error] scala.util.Try's type parameters do not match type T's expected parameters:
[error] class Try has one type parameter, but type T has none
[error] bind[SttpBackend[Try, Nothing]].toProvider[SttpBackendProvider]
[error] ` ^
SttpBackendProvider looks like:
def get: SttpBackend[Try, Nothing] = TryHttpURLConnectionBackend(opts)
complete example in scastie
interesting that version scalaguice 4.1.0 show this error, but latest 4.2.2 shows error inside it with converting Nothing to JavaType
I believe you hit two different bugs in the Scala-Guice one of which is not fixed yet (and probably even not submitted yet).
To describe those issues I need a fast intro into how Guice and Scala-Guice work. Essentially what Guice do is have a mapping from type onto the factory method for an object of that type. To support some advanced features types are mapped onto some internal "keys" representation and then for each "key" Guice builds a way to construct a corresponding object. Also it is important that generics in Java are implemented using type erasure. That's why when you write something like:
bind(classOf[SttpBackend[Try, Nothing]]).toProvider(classOf[SttpBackendProvider])
in raw-Guice, the "key" actually becomes something like "com.softwaremill.sttp.SttpBackend". Luckily Guice developers have thought about this issue with generics and introduced TypeLiteral[T] so you can convey the information about generics.
Scala type system is more reach than in Java and it has some better reflection support from the compiler. Scala-Guice exploits it to map Scala-types on those more detailed keys automatically. Unfortunately it doesn't always work perfectly.
The first issue is the result of the facts that the type SttpBackend is defined as
trait SttpBackend[R[_], -S]
so it uses it expects its first parameter to be a type constructor; and that originally Scala-Guice used the scala.reflect.Manifest infrastructure. AFAIU such higher-kind types are not representable as Manifest and this is what the error in your question really says.
Luckily Scala has added a new scala.reflect.runtime.universe.TypeTag infrastructure to tackle this issue in a better and more consistent way and the Scala-Guice migrated to its usage. That's why with the newer version of Scala-Guice the compiler error goes away. Unfortunately there is another bug in the Scala-Guice that makes the code fail in runtime and it is a lack of handling of the Nothing Scala type. You see, the Nothing type is a kind of fake one on the JVM. It is one of the things where the Scala type system is more reach than the Java one. There is no direct mapping for Nothing in the JVM world. Luckily there is no way to create any value of the type Nothing. Unfortunately you still can create a classOf[Nothing]. The Scala-to-JVM compiler handles it by using an artificial scala.runtime.Nothing$. It is not a part of the public API, it is implementation details of specifically Scala over JVM. Anyway this means that the Nothing type needs additional handling when converting into the Guice TypeLiteral and there is none. There is for Any the cousin of Nothing but not for Nothing (see the usage of the anyType in TypeConversions.scala).
So there are really two workarounds:
Use raw Java-based syntax for Guice instead of the nice Scala-Guice one:
bind(new TypeLiteral[SttpBackend[Try, Nothing]]() {})
.toInstance(sttpBackend) // or to whatever
See online demo based on your example.
Patch the TypeConversions.scala in the Scala-Guice as in:
private[scalaguice] object TypeConversions {
private val mirror = runtimeMirror(getClass.getClassLoader)
private val anyType = typeOf[Any]
private val nothingType = typeOf[Nothing] // added
...
def scalaTypeToJavaType(scalaType: ScalaType): JavaType = {
scalaType.dealias match {
case `anyType` => classOf[java.lang.Object]
case `nothingType` => classOf[scala.runtime.Nothing$] //added
...
I tried it locally and it seems to fix your example. I didn't do any extensive tests so it might have broken something else.

Static Code Analyzer to enforce Type Annotation in Scala

Is there any static code analyzer that can be used to enforce Type Annotation in Scala. For example, when a developer writes a statement without type annotation as show in the example below, he should get a compile time error
val name="sometime" //This should throw compile time error
This is what I expect the developer to write,
val name: String = "somename" // Type annotation 'String' explicitly specified
I am able to enforce few good practices using Scalastyle plugin in sbt(which throws compile time error when any of the rules specified for ScalastylePlugin is not followed). But I could find any rule that enforce type annotation
PS : Scalastyle does provide provision to create CustomRules(by extending the class ScalariformChecker). But I am just looking for a way to avoid developing custom code

Scala Macro - error referencing class symbol "not found: value <class>"

I'm trying to create a Scala macro that generates code like:
val x = new com.foo.MyClass()
where com.foo.MyClass is definitely on the classpath at compile time and run time in the project using the macro.
I'm using the following c.Tree to generate the code:
Apply(Select(New(Ident(TermName("com.foo.MyClass"))), termNames.CONSTRUCTOR), List())
Printing the output of the show and showRaw commands indicate that the correct code is generated, however it seems that com.foo.MyClass either isn't on the class path during macro expansion or during compilation immediately after.
I'm seeing the following error generated at the usage point of the macro (the macro impl itself is defined in a separate project):
[ERROR] /src/main/java/foo/MyWhatever.scala:10: not found: value com.foo.MyClass
[ERROR] MyMacros.someMacro(someInput)
[ERROR]
Why is it failing to find this class on the classpath even though it's a Java file in the same project? I tried -Ymacro-debug-verbose and com.foo.MyClass isn't in the output, but a bunch of other Java & Scala classes are. I can't find a pattern to which classes are on the classpath for the Macro expansion.
Thanks for any help!
Okay! I managed to answer my own question. It turns out it works to use c.mirror.staticClass("com.foo.MyClass") to use compile-time reflection to get a class Symbol, then use Quasi-quotes.
My solution:
val classSymbol = c.mirror.staticClass("com.foo.MyClass")
val newClassTree = q"new ${classSymbol.toType}()"
c.Expr { newClassTree } // Success! This compiles and runs

toString on a negative number doesn't compile in Scala Worksheet

If I create a Scala Worksheet in Eclipse as follows:
object negative {
2.toString //> res0: String = 2
(2).toString //> res1: String = 2
// compile error
(-2).toString
}
the final line causes a compile error:
';' expected but ')' found. illegal start of simple expression
However, the same three lines compile and run fine within a normal Scala source file.
Why does this not work in the worksheet?
This is using Eclipse 3.7.2, Scala IDE 3.0.0.v-2_10, Scala Worksheet 0.1.4.v-2_10
[Updated: this question originally used toBinaryString, but the problem occurs even with toString, so I have simplified it]
It is a bug. The code in the main object (the first one) of a worksheet is instrumented before being executed. In the 2 mentioned case, the result of the instrumentation is not valid Scala code.
But it is only a problem if the code is at the top level in the main object. If the code is moved to a function or a different object in the same file, it works fine.
Eclipse worksheets are quite beta; for example last I checked, it couldn't handle a #tailrec decoration on a function.
So this is most probably a bug or limitation in Eclipse. After all, the feature seems quite new, and there are many other bugs.
(-2).toBinaryString
gives same error for me.
Note that java.lang.Integer.toBinaryString(-2)works just fine.

How to define trait for adding to Seq?

I have a beginners Scala question. I have a class, Sample which extends the trait SampleAPI. Now I'm trying to build a sequence of Sample instances using seq. I will look something like this:
var samples: Seq[SampleAPI] = Seq()
for(...) {
samples :+= new Sample(...))
}
This gives me the following compiler error: "type mismatch; found : Seq[java.lang.Object] required: Seq[se.uu.medsci.queue.setup.SampleAPI]"
So I tried:
samples :+= (new Sample(sampleName, this, illuminaXMLReportReader)).asInstanceOf[SampleAPI]
Which instead throws a runtime exception, saying that Sample cannot be bast to SampleAPI. I guess that this comes down to a problem in my understanding of the use of traits in Scala. Any help in figuring this out would be much appreciated.
Is the compiler error coming up on this line?
samples :+= new Sample(...))
If so, I think the problem is that your Sample class doesn't actually extend SampleAPI.
What's happening has to do with the contravariant type parameter of the List type in Scala. If you start with a List[SampleAPI], then add a Sample to that list, it needs to find the least-upper-bound on the types included in the list to use as the new type parameter. If Sample is a SampleAPI, then the least-upper-bound is just SampleAPI and you get a List[SampleAPI] as the result of the :+= operation. However, if Sample is not a SampleAPI then the least-upper-bound on the two types is just Object, hence your compiler error saying that it was expecting a Seq[SampleAPI] but found a Seq[Object].