This post looks at a few ways to create manifests as well as how to compare manifests. The goal is to create a method that can be used in testing to require that a certain exception is thrown during a code block:
- scala> intercepts[Exception] {println("hi :)")}
- hi :)
- Expected java.lang.Exception but instead no exception was raised
The code snippet above is a failure because println does not throw an exception. In addition to requiring manifests this code snippet also is a custom control structure, for more information on those see Control Structure Tag
But before writing the intercepts methods a short inspection of the new manifest comparison operators:
- scala> import scala.reflect.{
- | Manifest, ClassManifest
- | }
- import scala.reflect.{Manifest, ClassManifest}
- // from class creates a manifest object given a class object
- scala> import ClassManifest.fromClass
- import ClassManifest.fromClass
- // several comparisons using <:<
- scala> fromClass(classOf[Exception]) <:< fromClass(classOf[Exception])
- res4: Boolean = true
- scala> fromClass(classOf[Exception]) <:< fromClass(classOf[RuntimeException])
- res5: Boolean = false
- scala> fromClass(classOf[Exception]) <:< fromClass(classOf[AssertionError])
- res6: Boolean = false
- // now the opposite operator >:>
- scala> fromClass(classOf[Exception]) >:> fromClass(classOf[AssertionError])
- res7: Boolean = false
- scala> fromClass(classOf[Exception]) >:> fromClass(classOf[RuntimeException])
- res8: Boolean = true
- scala> fromClass(classOf[Exception]) >:> fromClass(classOf[Error])
- res9: Boolean = false
- scala> fromClass(classOf[Exception]) >:> fromClass(classOf[Throwable])
- res10: Boolean = false
- // the method singleType creates a manifest given an object
- scala> ClassManifest.singleType(new RuntimeException())
- res12: scala.reflect.Manifest[Nothing] = java.lang.RuntimeException.type
- scala> ClassManifest.singleType(new RuntimeException()) <:< fromClass(classOf[Throwable])
- res13: Boolean = true
- scala> fromClass(classOf[Exception]) <:< fromClass(classOf[Throwable])
- res14: Boolean = true
Now the implementation of intercepts:
- scala> import scala.reflect.{
- | Manifest, ClassManifest
- | }
- import scala.reflect.{Manifest, ClassManifest}
- scala>
- scala> import ClassManifest.singleType
- import ClassManifest.singleType
- scala> def intercepts[E <: Throwable](test : => Unit)(implicit m:Manifest[E]) : Unit = {
- | import Predef.{println => fail}
- | try {
- | test
- | // this is a failure because test is expected to throw an exception
- | fail("Expected "+m.toString+" but instead no exception was raised")
- | }catch{
- | // this checks that the expected type (m) is a superclass of the class of e
- | case e if (m >:> singleType(e)) => ()
- | // any other error is handled here
- | case e => fail("Expected "+m.toString+" but instead got "+e.getClass)
- | }
- | }
- intercepts: [E <: Throwable](test: => Unit)(implicit m: scala.reflect.Manifest[E])Unit
- scala> intercepts[Exception] {println("hi :)")}
- hi :)
- Expected java.lang.Exception but instead no exception was raised
- scala> intercepts[Exception] { throw new IllegalArgumentException("why not throw this :)")}
- scala> intercepts[Exception] { throw new AssertionError("The method should complain")}
- Expected java.lang.Exception but instead got class java.lang.AssertionError
Hi Jesse,
ReplyDeleteThanks again for that post, I didn't have time to check out the comparison operators on Manifests.
BTW there are 2 typos:
"Manifests were originally added to Java 2.7"
It's Scala 2.7.
And
"the method singeType creates" instead of
"the method singleType creates"
E.
Do you have a link to docs for the <:< and >:> operators? I've never seen them before and don't know where they are.
ReplyDeleteThanks Eric. I have fixed those errors
ReplyDeleteHi I don't know of Scala 2.8 docs that are online. These methods are only in Scala 2.8
ReplyDeleteScaladoc of Scala 2.8 nightly builds:
ReplyDeletehttp://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/index.html