diff --git a/common/shared/src/main/scala/org/specs2/execute/ResultExecution.scala b/common/shared/src/main/scala/org/specs2/execute/ResultExecution.scala index 8565c037ab..e652feae35 100644 --- a/common/shared/src/main/scala/org/specs2/execute/ResultExecution.scala +++ b/common/shared/src/main/scala/org/specs2/execute/ResultExecution.scala @@ -6,6 +6,7 @@ import control.Property import reflect.ClassName._ import text.NotNullStrings._ import java.util.regex.Pattern +import scala.util.control.NonFatal /** * This trait executes a Result and returns an appropriate value when a specs2 exception is thrown @@ -33,7 +34,7 @@ trait ResultExecution { outer => case e: AssertionError => Error(e) case e: java.lang.Error if simpleClassName(e) == "NotImplementedError" => Failure(e.getMessage.notNull, "", e.getStackTrace.toList, details = FromJUnitAssertionError) case e: java.lang.Error if simpleClassName(e) == "ExpectationError" => Failure(e.toString, "", e.getStackTrace.toList, details = FromExpectationError) - case t: Exception => Error(t) + case NonFatal(t) => Error(t) } /** execute a Result and rethrow any exception or throws an exception if it is not a success */ @@ -60,7 +61,7 @@ trait ResultExecution { outer => case e: AssertionError => throw ErrorException(Error(e)) case e: java.lang.Error if simpleClassName(e) == "NotImplementedError" => throw FailureException(Failure(e.getMessage.notNull, "", e.getStackTrace.toList, details = FromJUnitAssertionError)) case e: java.lang.Error if simpleClassName(e) == "ExpectationError" => throw FailureException(Failure(e.toString, "", e.getStackTrace.toList, details = FromExpectationError)) - case t: Exception => throw ErrorException(Error(t)) + case NonFatal(t) => throw ErrorException(Error(t)) } /** diff --git a/core/jvm/src/test/scala/org/specs2/specification/core/ExecutionSpec.scala b/core/jvm/src/test/scala/org/specs2/specification/core/ExecutionSpec.scala index de05bb45f8..273cd8b044 100644 --- a/core/jvm/src/test/scala/org/specs2/specification/core/ExecutionSpec.scala +++ b/core/jvm/src/test/scala/org/specs2/specification/core/ExecutionSpec.scala @@ -12,7 +12,11 @@ class ExecutionSpec(val env: Env) extends Specification with OwnEnv { def is = s A link is executed by getting the corresponding specification ref status in the Statistics store the Stats is the stats of the spec + specs += 1 $linkExecution - An execution can be created from a result throwing a FailureException $withFailureException + An execution can be created from a result throwing a FailureException + it will then create a failed result $withFailureException + + An execution can be created from a result throwing a fatal exception + it will then throw an ExecutionException exception $withFatalException """ @@ -35,6 +39,10 @@ class ExecutionSpec(val env: Env) extends Specification with OwnEnv { def is = s Execution.withEnv(_ => {throw new FailureException(failure); success}).result(env) === failure } + def withFatalException = { + Execution.withEnv(_ => {throw new java.lang.NoSuchMethodError("boom"); success}).result(env) must throwAn[ExecutionException] + } + /** * HELPERS */ diff --git a/core/shared/src/main/scala/org/specs2/specification/core/Execution.scala b/core/shared/src/main/scala/org/specs2/specification/core/Execution.scala index dfd01cf5eb..5034f515fa 100644 --- a/core/shared/src/main/scala/org/specs2/specification/core/Execution.scala +++ b/core/shared/src/main/scala/org/specs2/specification/core/Execution.scala @@ -137,9 +137,14 @@ case class Execution(run: Option[Env => Future[() => Result]] = None, env.setContextClassLoader() val timer = startSimpleTimer - + val timedFuture = TimedFuture({ es => - r(env).map(action => (action(), timer.stop)) + r(env).flatMap { action => + try Future.successful((action(), timer.stop)) + catch { case t: Throwable => + Future.failed(t) + } + } }, to) val future = timedFuture.runNow(env.executorServices).recoverWith { case e: FailureException =>