From a446f227a562fb585c599e2aea14c1dfbc3251f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Gonc=CC=A7alves?= Date: Fri, 27 Dec 2019 01:37:58 +0000 Subject: [PATCH] Add Scaladoc to public matcher API --- .../akka/testkit/specs2/AkkaMatchers.scala | 17 +++++ .../testkit/specs2/AkkaTypedMatchers.scala | 17 +++++ .../akka/testkit/specs2/api/package.scala | 75 ++++++++++++++++++- 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaMatchers.scala b/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaMatchers.scala index 04b259d..bf40beb 100644 --- a/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaMatchers.scala +++ b/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaMatchers.scala @@ -11,6 +11,10 @@ import net.ruippeixotog.akka.testkit.specs2.impl.Matchers._ trait AkkaMatchers { + /** + * A `Matcher` expecting a probe to have received a message within the default timeout. + * Additional methods can be chained to constrain the expected message. + */ def receive: UntypedReceiveMatcher[TestKitBase] = { akkaClassicReceiveMatcher( { msg => s"Received message '$msg'" }, @@ -18,6 +22,12 @@ trait AkkaMatchers { _.remainingOrDefault) } + /** + * A `Matcher` expecting a probe to have received a message within the provided timeout. + * Additional methods can be chained to constrain the expected message. + * + * @param max the timeout for a message to be received + */ def receiveWithin(max: FiniteDuration): UntypedReceiveMatcher[TestKitBase] = { akkaClassicReceiveMatcher( { msg => s"Received message '$msg' within $max" }, @@ -25,7 +35,14 @@ trait AkkaMatchers { { _ => max }) } + /** + * An alias for [[receive]]. + */ def receiveMessage: UntypedReceiveMatcher[TestKitBase] = receive + + /** + * An alias for [[receiveWithin]]. + */ def receiveMessageWithin(max: FiniteDuration): UntypedReceiveMatcher[TestKitBase] = receiveWithin(max) private[this] def akkaClassicReceiveMatcher( diff --git a/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaTypedMatchers.scala b/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaTypedMatchers.scala index 1b629bf..972e3e9 100644 --- a/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaTypedMatchers.scala +++ b/src/main/scala/net/ruippeixotog/akka/testkit/specs2/AkkaTypedMatchers.scala @@ -11,6 +11,10 @@ import net.ruippeixotog.akka.testkit.specs2.impl.Matchers.ReceiveMatcherImpl trait AkkaTypedMatchers { + /** + * A `Matcher` expecting a probe to have received a message within the default timeout. + * Additional methods can be chained to constrain the expected message. + */ def receive[Msg]: ReceiveMatcher[TestProbe[Msg], Msg] = { akkaTypedReceiveMatcher[Msg]( { msg => s"Received message '$msg'" }, @@ -18,6 +22,12 @@ trait AkkaTypedMatchers { _.remainingOrDefault) } + /** + * A `Matcher` expecting a probe to have received a message within the provided timeout. + * Additional methods can be chained to constrain the expected message. + * + * @param max the timeout for a message to be received + */ def receiveWithin[Msg](max: FiniteDuration): ReceiveMatcher[TestProbe[Msg], Msg] = { akkaTypedReceiveMatcher[Msg]( { msg => s"Received message '$msg' within $max" }, @@ -25,7 +35,14 @@ trait AkkaTypedMatchers { { _ => max }) } + /** + * An alias for [[receive]]. + */ def receiveMessage[Msg]: ReceiveMatcher[TestProbe[Msg], Msg] = receive + + /** + * An alias for [[receiveWithin]]. + */ def receiveMessageWithin[Msg](max: FiniteDuration): ReceiveMatcher[TestProbe[Msg], Msg] = receiveWithin(max) private[this] def akkaTypedReceiveMatcher[Msg]( diff --git a/src/main/scala/net/ruippeixotog/akka/testkit/specs2/api/package.scala b/src/main/scala/net/ruippeixotog/akka/testkit/specs2/api/package.scala index cae1cbe..55424fa 100644 --- a/src/main/scala/net/ruippeixotog/akka/testkit/specs2/api/package.scala +++ b/src/main/scala/net/ruippeixotog/akka/testkit/specs2/api/package.scala @@ -5,25 +5,96 @@ import scala.reflect.ClassTag import org.specs2.execute.AsResult import org.specs2.matcher.Matcher +/** + * The API used to transform and compose matchers for received messages. + */ package object api { + trait BaseReceiveMatcher[P, A] extends Matcher[P] trait SkippableReceiveMatcher[P, A] extends BaseReceiveMatcher[P, A] { + + /** + * Skips non-matching messages until a matching one is received or a timeout occurs. Commonly used when the order of + * received messages cannot be guaranteed and the probe may receive other messages, like heartbeats. + * + * @return a new matcher that skips non-matching messages until a matching one is received or a timeout occurs. + */ def afterOthers: BaseReceiveMatcher[P, A] } trait ReceiveMatcher[P, A] extends SkippableReceiveMatcher[P, A] { - def unwrap[B](f: A => B): ReceiveMatcher[P, B] - def unwrapPf[B](f: PartialFunction[A, B]): ReceiveMatcher[P, B] + + /** + * Constrains the received messages to be of a given subtype. + * + * @tparam B the expected subtype of messages + * @return a new matcher that expects a probe to have received messages of type `B`. + */ def ofSubtype[B <: A: ClassTag](implicit ev: A <:< AnyRef): ReceiveMatcher[P, B] + /** + * Checks that the received message is equal to the given value. + * + * @param msg the expected message + * @return a new matcher that expects a probe to have received `msg`. + */ def apply(msg: A): SkippableReceiveMatcher[P, A] + + /** + * Checks that the received message satisfies a predicate or a function applying further checks. + * + * @param f the predicate or function applying further checks + * @return a new matcher that expects a probe to have received messages satisfying `f`. + */ def which[R: AsResult](f: A => R): SkippableReceiveMatcher[P, A] + + /** + * Checks that the received message satisfies a partial predicate or function applying further checks. + * + * @param f the partial predicate or function applying further checks + * @return a new matcher that expects a probe to have received messages satisfying `f`. + */ def like[R: AsResult](f: PartialFunction[A, R]): SkippableReceiveMatcher[P, A] + + /** + * Checks that the probe received a sequence of messages in order. The timeout is applied to the whole sequence and + * not per message (i.e. all the messages have to be received before the timeout duration). + * + * @param msgs the expected sequence of messages + * @return a new matcher that expects a probe to have received all the messages in `msgs` in order. + */ def allOf(msgs: A*): SkippableReceiveMatcher[P, Seq[A]] + + /** + * Applies a function to the received messages before checks. Commonly used to unwrap data in envelope-like + * messages. + * + * @param f the function to apply to messages + * @tparam B the return type of the function + * @return a new matcher that applies `f` to messages before checking them. + */ + def unwrap[B](f: A => B): ReceiveMatcher[P, B] + + /** + * Applies a partial function to the received messages before checks. Messages for which the function is undefined + * count as failures. Commonly used to unwrap data in envelope-like messages. + * + * @param f the partial function to apply to messages + * @tparam B the return type of the function + * @return a new matcher that applies `f` to messages before checking them. + */ + def unwrapPf[B](f: PartialFunction[A, B]): ReceiveMatcher[P, B] } trait UntypedReceiveMatcher[P] extends ReceiveMatcher[P, Any] { + + /** + * Constrains the received messages to be of a given type. + * + * @tparam A the expected type of messages + * @return a new matcher that expects a probe to have received messages of type `A`. + */ def apply[A: ClassTag]: ReceiveMatcher[P, A] } }