From 9671aaf060357a8aba35a11b05651885f100fa2a Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Thu, 14 Mar 2013 19:01:01 -0500 Subject: add lives_ok/dies_ok/throws_ok/exception fixes gh-2 --- .../scala/com/iinteractive/test/TestMore.scala | 74 +++++++++++++++ .../com/iinteractive/test/ExceptionTest.scala | 100 +++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 src/test/scala/com/iinteractive/test/ExceptionTest.scala 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") +} -- cgit v1.2.3