aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2013-03-14 19:01:01 -0500
committerJesse Luehrs <doy@tozt.net>2013-03-14 19:08:54 -0500
commit9671aaf060357a8aba35a11b05651885f100fa2a (patch)
treeab553f39d51d1aaa0cb51af119a8f5fe41935687
parent7a00ccf0a468cd74543e3c65f8ebecab9629e10d (diff)
downloadscala-test-more-9671aaf060357a8aba35a11b05651885f100fa2a.tar.gz
scala-test-more-9671aaf060357a8aba35a11b05651885f100fa2a.zip
add lives_ok/dies_ok/throws_ok/exception
fixes gh-2
-rw-r--r--src/main/scala/com/iinteractive/test/TestMore.scala74
-rw-r--r--src/test/scala/com/iinteractive/test/ExceptionTest.scala100
2 files changed, 174 insertions, 0 deletions
diff --git a/src/main/scala/com/iinteractive/test/TestMore.scala b/src/main/scala/com/iinteractive/test/TestMore.scala
index b5bf6f4..9eedf68 100644
--- a/src/main/scala/com/iinteractive/test/TestMore.scala
+++ b/src/main/scala/com/iinteractive/test/TestMore.scala
@@ -1,6 +1,8 @@
package com.iinteractive.test
+import scala.reflect.{ClassTag,classTag}
import scala.util.matching.Regex
+import scala.util.{Try,Success,Failure}
import com.iinteractive.test.tap.TestBuilder
@@ -297,6 +299,58 @@ class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit {
def fail (desc: String): Boolean =
ok(false, desc)
+ /** Assert that the given block of code doesn't throw an exception.
+ *
+ * @example `lives_ok { myObj.explode }`
+ */
+ def lives_ok (body: => Unit): Boolean = {
+ val gotOpt = exception(body)
+ val success = gotOpt.isEmpty
+ val desc = "didn't throw an exception"
+ val message = gotOpt.map(livesOkMessage).getOrElse("")
+ testWithDesc(success, desc, message)
+ }
+
+ /** Assert that the given block of code throws an exception.
+ *
+ * @example `dies_ok[MyException] { myObj.explode }`
+ */
+ def dies_ok[T <: Throwable : ClassTag] (body: => Unit): Boolean = {
+ val gotOpt = exception(body)
+ val success = gotOpt.map { got =>
+ classTag[T].runtimeClass.isAssignableFrom(got.getClass)
+ }.getOrElse(false)
+ val desc = "threw a " + classTag[T].toString + " exception"
+ val message = gotOpt.map(diesOkMessage[T]).getOrElse(diesOkMessage[T])
+ testWithDesc(success, desc, message)
+ }
+
+ /** Assert that the given block of code throws an exception, and that the
+ * exception that it throws is equal to the passed exception.
+ *
+ * @example `throws_ok(new MyException("foo")) { myObj.explode }`
+ */
+ def throws_ok (e: Throwable)(body: => Unit): Boolean = {
+ val gotOpt = exception(body)
+ val success = gotOpt.map { got => got == e }.getOrElse(false)
+ val desc = "threw " + e.toString
+ val message = gotOpt.map(
+ throwsOkMessage(_, e)
+ ).getOrElse(throwsOkMessage(e))
+ testWithDesc(success, desc, message)
+ }
+
+ /** Runs a block of code, returning the exception that it throws, or None if
+ * no exception was thrown. Not an assertion on its own, but can be used to
+ * create more complicated assertions about exceptions.
+ *
+ * @example `is(exception { myObj.explode }, None)`
+ */
+ def exception (body: => Unit): Option[Throwable] = Try(body) match {
+ case Success(_) => None
+ case Failure(e) => Some(e)
+ }
+
/** Output a comment to `Console.err`. This is intended to be visible to
* users even when running the test under a summarizing harness.
*
@@ -409,6 +463,26 @@ class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit {
" '" + got + "'\n" +
" matches '" + rx + "'\n"
+ private def livesOkMessage(got: Throwable) =
+ " got: " + got + "\n" +
+ " expected: normal exit\n"
+
+ private def diesOkMessage[T: ClassTag] =
+ " got: normal exit\n" +
+ " expected: a " + classTag[T].toString + " exception\n"
+
+ private def diesOkMessage[T: ClassTag](got: Throwable) =
+ " got: " + got + "\n" +
+ " expected: a " + classTag[T].toString + " exception\n"
+
+ private def throwsOkMessage[T](e: T) =
+ " got: normal exit\n" +
+ " expected: " + e + "\n"
+
+ private def throwsOkMessage[T](got: Throwable, e: T) =
+ " got: " + got + "\n" +
+ " expected: " + e + "\n"
+
private def testWithDesc (
cond: Boolean,
desc: String
diff --git a/src/test/scala/com/iinteractive/test/ExceptionTest.scala b/src/test/scala/com/iinteractive/test/ExceptionTest.scala
new file mode 100644
index 0000000..62c9278
--- /dev/null
+++ b/src/test/scala/com/iinteractive/test/ExceptionTest.scala
@@ -0,0 +1,100 @@
+package com.iinteractive.test
+
+import java.io.ByteArrayOutputStream
+
+import com.iinteractive.test.tap.Parser
+
+class ExceptionTest extends TestMore {
+ val lineZero = Thread.currentThread.getStackTrace()(1).getLineNumber + 3
+ def line (offset: Int) = lineZero + offset
+
+ private class MyBasicTest extends TestMore {
+ private case class MyException(msg: String)
+ extends RuntimeException(msg)
+ private case class OtherException(msg: String)
+ extends RuntimeException(msg)
+
+ lives_ok {
+ val _ = "no exception"
+ }
+ lives_ok {
+ throw MyException("foo")
+ }
+
+ dies_ok[MyException] {
+ val _ = "no exception"
+ }
+ dies_ok[MyException] {
+ throw OtherException("foo")
+ }
+ dies_ok[MyException] {
+ throw MyException("foo")
+ }
+
+ throws_ok(MyException("foo")) {
+ val _ = "no exception"
+ }
+ throws_ok(MyException("foo")) {
+ throw MyException("bar")
+ }
+ throws_ok(MyException("foo")) {
+ throw MyException("foo")
+ }
+
+ is(
+ exception { val _ = "no exception" },
+ None
+ )
+ is(
+ exception { throw MyException("foo") },
+ Some(MyException("foo"))
+ )
+ }
+
+ val out = new ByteArrayOutputStream
+ val exitCode = Console.withOut(out) {
+ Console.withErr(out) {
+ (new MyBasicTest).run
+ }
+ }
+
+ is((new Parser).parse(out).exitCode, 5, "got the right plan")
+ is(exitCode, 5, "got the right plan")
+
+ val expected =
+ ("""^ok 1 - didn't throw an exception
+not ok 2 - didn't throw an exception
+# Failed test 'didn't throw an exception'
+# at ExceptionTest.scala line """ + line(9) + """.
+# got: [^\s]*MyException[^\n]*foo[^\n]*
+# expected: normal exit
+not ok 3 - threw a [^\s]*MyException exception
+# Failed test 'threw a [^\s]*MyException exception'
+# at ExceptionTest.scala line """ + line(13) + """.
+# got: normal exit
+# expected: a [^\s]*MyException exception
+not ok 4 - threw a [^\s]*MyException exception
+# Failed test 'threw a [^\s]*MyException exception'
+# at ExceptionTest.scala line """ + line(16) + """.
+# got: [^\s]*OtherException[^\n]*foo[^\n]*
+# expected: a [^\s]*MyException exception
+ok 5 - threw a [^\s]*MyException exception
+not ok 6 - threw [^\s]*MyException[^\n]*foo[^\n]*
+# Failed test 'threw [^\s]*MyException[^\n]*foo[^\n]*'
+# at ExceptionTest.scala line """ + line(23) + """.
+# got: normal exit
+# expected: [^\s]*MyException[^\n]*foo[^\n]*
+not ok 7 - threw [^\s]*MyException[^\n]*foo[^\n]*
+# Failed test 'threw [^\s]*MyException[^\n]*foo[^\n]*'
+# at ExceptionTest.scala line """ + line(26) + """.
+# got: [^\s]*MyException[^\n]*bar[^\n]*
+# expected: [^\s]*MyException[^\n]*foo[^\n]*
+ok 8 - threw [^\s]*MyException[^\n]*foo[^\n]*
+ok 9
+ok 10
+1..10
+# Looks like you failed 5 tests of 10.
+$""").r
+
+ like(out.toString, expected, "correct tap")
+}