diff --git a/matcher/shared/src/main/scala/org/specs2/matcher/TryMatchers.scala b/matcher/shared/src/main/scala/org/specs2/matcher/TryMatchers.scala index 847302ed57..8b84e1191f 100644 --- a/matcher/shared/src/main/scala/org/specs2/matcher/TryMatchers.scala +++ b/matcher/shared/src/main/scala/org/specs2/matcher/TryMatchers.scala @@ -3,6 +3,7 @@ package matcher import scala.reflect.ClassTag import util.* +import execute.{Result, AsResult} import execute.ResultImplicits.* import org.specs2.matcher.describe.Diffable import text.NotNullStrings.* @@ -45,11 +46,17 @@ trait TryMatchers: object TryeMatchers extends TryMatchers -case class TrySuccessMatcher[T]() extends OptionLikeMatcher[Try[T], T]("a Success", (_: Try[T]).toOption): - def withValue(t: ValueCheck[T]) = TrySuccessCheckedMatcher(t) +case class TrySuccessMatcher[T]() extends Matcher[Try[T]]: + def apply[S <: Try[T]](value: Expectable[S]): Result = checkSuccess(value, ValueCheck.alwaysOk) -case class TrySuccessCheckedMatcher[T](check: ValueCheck[T]) - extends OptionLikeCheckedMatcher[Try[T], T]("a Success", (_: Try[T]).toOption, check) + def withValue(t: ValueCheck[T]): Matcher[Try[T]] = TrySuccessCheckedMatcher(t) + + def which[R: AsResult](f: T => R): Matcher[Try[T]] = new TrySuccessCheckedMatcher(f) + + def like[R: AsResult](f: PartialFunction[T, R]): Matcher[Try[T]] = new TrySuccessCheckedMatcher(f) + +case class TrySuccessCheckedMatcher[T](check: ValueCheck[T]) extends Matcher[Try[T]]: + def apply[S <: Try[T]](value: Expectable[S]): Result = checkSuccess(value, check) case class TryFailureMatcher[T]() extends OptionLikeMatcher[Try[T], Throwable]("a Failure", (_: Try[T]).failed.toOption): @@ -65,3 +72,15 @@ case class TryFailureMatcher[T]() }) case class TryFailureCheckedMatcher[T](check: ValueCheck[Throwable]) extends OptionLikeCheckedMatcher[Try[T], Throwable]("a Failure", (_: Try[T]).failed.toOption, check) + +private def checkSuccess[T](value: Expectable[Try[T]], check: ValueCheck[T]): Result = value.value match + case Success(v) => + val r = check.check(v) + val koMessage = s"${value.description} is a Success but ${r.message}" + r match + case execute.Failure(_, _, _, details) => Result.result(false, koMessage, details) + case _ => Result.result(r.isSuccess, koMessage) + case Failure(e) => + execute.Failure( + s"${value.description} is not a Success\n\nFailed with ${e.getMessage}:\n\n${e.getStackTrace.mkString("\n")}" + ) diff --git a/tests/shared/src/test/scala/org/specs2/matcher/TryMatchersSpec.scala b/tests/shared/src/test/scala/org/specs2/matcher/TryMatchersSpec.scala index d77910ea53..695a31e34b 100644 --- a/tests/shared/src/test/scala/org/specs2/matcher/TryMatchersSpec.scala +++ b/tests/shared/src/test/scala/org/specs2/matcher/TryMatchersSpec.scala @@ -18,14 +18,14 @@ class TryMatchersSpec extends Spec with TryMatchers with ResultMatchers { ${(Succeeded(1) must beASuccessfulTry.which(_ > 0))} ${(Succeeded(1) must beASuccessfulTry .which(_ < 0)) returns "Success(1) is a Success but the function returns 'false' on '1'"} - ${(Failed[I](e) must beASuccessfulTry.which(_ > 0)) returns "Failure(boom) is not a Success"} + ${(Failed[I](e) must beASuccessfulTry.which(_ > 0)) returns "Failure(boom) is not a Success\n\nFailed with boom:\n\n"} ${Succeeded(1) must beASuccessfulTry[Int].like { case a if a > 0 => ok }} ${(Succeeded(1) must not(beASuccessfulTry[Int].like { case a => a must be_>=(0) })) returns "Expectation failed: 'Success(1) is a Success but 1 is strictly less than 0'"} ${Succeeded(1) must not(beASuccessfulTry.withValue(2))} ${Failed[I](e) must not(beASuccessfulTry)} ${Failed[I](e) must not(beASuccessfulTry.withValue(2))} - ${(Failed[I](e) must beSuccessfulTry) returns "Failure(boom) is not a Success"} + ${(Failed[I](e) must beSuccessfulTry) returns "Failure(boom) is not a Success\n\nFailed with boom:\n\n"} ${(Succeeded(1) must beSuccessfulTry.withValue(2)) returns "Success(1) is a Success but 1 != 2"} beAFailure checks if an element is Failure(_)