diff --git a/matcher/src/main/scala/org/specs2/matcher/ExceptionMatchers.scala b/matcher/src/main/scala/org/specs2/matcher/ExceptionMatchers.scala index f75d6a9607..b2cd69bf2d 100644 --- a/matcher/src/main/scala/org/specs2/matcher/ExceptionMatchers.scala +++ b/matcher/src/main/scala/org/specs2/matcher/ExceptionMatchers.scala @@ -55,6 +55,7 @@ trait ExceptionBaseMatchers extends Expectations { checkMatchResult(value, (e: Throwable) => classType(e), f) } } + private val classType = (e: Throwable) => { errorMustBeThrownIfExceptionIsExpected(e, klass) diff --git a/matcher/src/main/scala/org/specs2/matcher/FutureMatchers.scala b/matcher/src/main/scala/org/specs2/matcher/FutureMatchers.scala index b4cb079fea..f836e50c6a 100644 --- a/matcher/src/main/scala/org/specs2/matcher/FutureMatchers.scala +++ b/matcher/src/main/scala/org/specs2/matcher/FutureMatchers.scala @@ -38,12 +38,21 @@ trait FutureMatchers extends Expectations with ConcurrentExecutionContext { } } + def await[T](m: Matcher[T]): Matcher[Future[T]] = awaitFor(m)() def await[T](m: Matcher[T])(retries: Int = 0, timeout: FiniteDuration = 1.seconds): Matcher[Future[T]] = awaitFor(m)(retries, timeout) private def awaitFor[T](m: Matcher[T])(retries: Int = 0, timeout: FiniteDuration = 1.seconds): Matcher[Future[T]] = new Matcher[Future[T]] { def apply[S <: Future[T]](a: Expectable[S]) = { - val r = a.value.map(v => createExpectable(v).applyMatcher(m).toResult).await(retries, timeout) - result(r.isSuccess, r.message, r.message, a) + try { + val r = a.value.map(v => createExpectable(v).applyMatcher(m).toResult).await(retries, timeout) + result(r.isSuccess, r.message, r.message, a) + } catch { + // if awaiting on the future throws an exception because it was a failed future + // there try to match again because the matcher can be a `throwA` matcher + case t: Throwable => + val r = createExpectable(throw t).applyMatcher(m).toResult + result(r.isSuccess, r.message, r.message, a) + } } } } diff --git a/tests/src/test/scala/org/specs2/matcher/FutureMatchersSpec.scala b/tests/src/test/scala/org/specs2/matcher/FutureMatchersSpec.scala index 84fc0395ed..bf1dbaba37 100644 --- a/tests/src/test/scala/org/specs2/matcher/FutureMatchersSpec.scala +++ b/tests/src/test/scala/org/specs2/matcher/FutureMatchersSpec.scala @@ -21,6 +21,10 @@ class FutureMatchersSpec extends Specification with Groups with NoTimeConversion A `Future` returning a `Matcher[T]` can be transformed into a `Result` ${ Future(1 === 1).await } + A `throwA[T]` matcher can be used to match a failed future with the `await` method + ${ Future.failed[Int](new RuntimeException) must throwA[RuntimeException].await } + ${ { Future.failed[Int](new RuntimeException) must be_===(1).await } must throwA[RuntimeException] } + """ // the current execution context can be overridden here