Is there some way to make a suspending call within...
# kotest
v
Is there some way to make a suspending call within a custom matcher? Something like
Copy code
fun beValid(): Matcher<PathLike> {
    return Matcher { path ->
        MatcherResult(
            validate(YAML.parse(readFile(path, utf8))),
            { "..." },
            { "..." }
        )
    }
}
just in working
l
What is the suspend call here?
validate
?
Or is it inside the message?
I'd say you can probably just make your matchers suspend and call it inside a kotest spec, which should handle suspend functions seamlessly
v
readFile
is the suspending call
Right now I have
readFile(path.join(dataDir, "foo.yml"), utf8) should beValid()
but it would be nicer to have
path.join(dataDir, "foo.yml") should beValid()
.
If I make the
beValid()
suspend, this does not help as I need the
data
argument for the suspending call. And the
Matcher.invoke
does not take a suspending function.
And
Matcher.test
is also not suspending
e
Can't you move the
readFile
outside of the matcher? I.e
path should beValid()
->
readFile(path) should beValid()
v
That's what I have and would like to change as it is (hopefully) unnecessary repetition in each assertion line. :-)
p
alternatively, have a
suspend fun PathLike.shouldBeValid() { readFile(this, utf8) should beValid() }
helper to make it nicer at the callsite - i.e.
path.shouldBeValid()
l
And
Matcher.test
is also not suspending
I wonder why it isn't. I think it probably should be. @sam?
s
Cos the assertions were built before coroutines existed
And becuase we wanted them usable in junit
v
So I take it is not possible, thanks. But the suspending
shouldBeValid
is a nice idea, thanks.
👍 1
p
would a
SuspendingMatcher
type and equivalent
suspend infix fun <T> T.should(matcher: SuspendingMatcher<T>)
be useful for those assertions? only usable from a suspend callsite of course (so no junit)
s
would have to check that the type inference picks up the right should, since the other should accepts an Any, but if it does then that would be a clever way of allowing suspending matchers
v
In this case the function is really nice, because I can also move the join call inside. So now it is just
"foo.yml".shouldBeValid()
with
Copy code
private suspend fun String.shouldBeValid(dataDir: String = goodDir): String {
    readFile(path.join(dataDir, this), utf8) should beValid()
    return this
}

private suspend fun String.shouldNotBeValid(dataDir: String = badDir): String {
    readFile(path.join(dataDir, this), utf8) shouldNot beValid()
    return this
}
(the parameters are mostly just for now when testing intentional test failure to see the proper error messages. 🙂)
But for other use-cases the
SuspendingMatcher
might indeed be helpful
Type inference should hopefully indeed pick up the right
should
as
SuspendingMatcher
is more specific than
Any
. Besides that as far as I can see
should
accepts
Matcher
, not
Any
, but other than that it should be the same.
s
oh yeah its shouldBe that is Any not should
👌 1