Skip to content

Commit bf25b58

Browse files
authored
Merge pull request #226 from LaurenceWarne/create-match-or-fail-fast
Create matchOrFailFast utility
2 parents 0b05439 + b97a9cb commit bf25b58

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

docs/features/expectations.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,18 @@ val list = List(1)
112112
} yield expect(y.contains(x))
113113
```
114114

115+
- Similarly `matchOrFailFast` can be used assert an expression matches a given pattern, and return it if so
116+
117+
```scala mdoc:compile-only
118+
for {
119+
b <- IO(Some(4))
120+
s <- matchOrFailFast[IO](b) {
121+
case Some(v) => v.toString
122+
}
123+
c <- IO("4")
124+
} yield expect.eql(s, c)
125+
```
126+
115127
## Example suite
116128

117129
```scala mdoc
@@ -221,6 +233,19 @@ object ExpectationsSuite extends SimpleIOSuite {
221233
_ <- expect(clue(h).isEmpty).failFast
222234
} yield success
223235
}
236+
237+
test("Failing fast match") {
238+
for {
239+
h <- IO.pure(Some(4))
240+
x <- matchOrFailFast[IO](h) {
241+
case Some(v) => v
242+
}
243+
g <- IO.pure(Option.empty[Int])
244+
y <- matchOrFailFast[IO](g) {
245+
case Some(v) => v
246+
}
247+
} yield expect.eql(x, y)
248+
}
224249
}
225250
```
226251

modules/core/shared/src/main/scala/weaver/Expectations.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,24 @@ object Expectations {
157157
))
158158
}
159159

160+
final private[weaver] class PartiallyAppliedMatchOrFailFast[F[_]](
161+
val dummy: Boolean = true)
162+
extends AnyVal {
163+
def apply[A, B](x: A)(
164+
pf: PartialFunction[A, B]
165+
)(
166+
implicit loc: SourceLocation,
167+
F: Sync[F],
168+
A: Show[A] = Show.fromToString[A]): F[B] =
169+
pf.lift(x).fold[F[B]] {
170+
Sync[F].raiseError(
171+
new ExpectationFailed(
172+
"Pattern did not match, got: " + x.show,
173+
NonEmptyList.of(loc)
174+
))
175+
}(Sync[F].pure)
176+
}
177+
160178
trait Helpers extends weaver.internals.ClueHelpers {
161179

162180
/**
@@ -231,6 +249,25 @@ object Expectations {
231249
else
232250
failure("Pattern did not match, got: " + x.show)
233251

252+
/**
253+
* Checks that a given expression matches a certain pattern, returning the
254+
* result of the partial function <code>pf</code> if so, fails otherwise.
255+
*
256+
* @example
257+
* {{{
258+
* val x = Some(4)
259+
* val otherSideEffect = IO.pure("4")
260+
* for {
261+
* b <- matchOrFailFast[IO](x) {
262+
* case Some(v) => v.toString
263+
* }
264+
* c <- otherSideEffect
265+
* } yield expect.eql(b, c)
266+
* }}}
267+
*/
268+
def matchOrFailFast[F[_]]: PartiallyAppliedMatchOrFailFast[F] =
269+
new PartiallyAppliedMatchOrFailFast[F]
270+
234271
/**
235272
* Alias for `forEach`
236273
*/

modules/framework-cats/shared/src/test/scala/ExpectationsTests.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package weaver
22
package framework
33
package test
44

5+
import cats.effect.IO
56
import cats.kernel.Eq
67

78
object ExpectationsTests extends SimpleIOSuite {
@@ -61,6 +62,24 @@ object ExpectationsTests extends SimpleIOSuite {
6162
})
6263
}
6364

65+
test("matchOrFailFast (success)") {
66+
matchOrFailFast[IO](Some(4)) {
67+
case Some(v) => v
68+
}.as(success)
69+
}
70+
71+
test("matchOrFailFast (failure)") {
72+
matchOrFailFast[IO](Option.empty[Int]) {
73+
case Some(v) => v
74+
}
75+
.attempt
76+
.map { either =>
77+
matches(either) { case Left(_: ExpectationFailed) =>
78+
success
79+
}
80+
}
81+
}
82+
6483
pureTest("expect.eql respects cats.kernel.Eq") {
6584
implicit val eqInt: Eq[Int] = Eq.allEqual
6685
expect.eql(0, 1)

0 commit comments

Comments
 (0)