Let's look at the documentation for the types and traits in question. Usually the required traits are implemented automatically on all the types where it is possible, and, in fact, if the type in question is not your own, the trait has to be implemented by the library. So, first of all we check the assert_cmd
docs to see what types can be used here.
There are two implementations which can be of interest for us:
impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P
where
P: Predicate<str>
impl<P> IntoOutputPredicate<P> for P
where
P: Predicate<[u8]>
Let's see now, what is the Predicate
. This ends in the predicates-core
crate, so it seems that at least some of the items from the predicates
crate (based on this core) will be possible to use.
Now, let's try the other way round - look through the docs for predicate::function
:
pub fn function<F, T>(function: F) -> FnPredicate<F, T>
where
F: Fn(&T) -> bool,
T: ?Sized,
Well then, we've got the type FnPredicate
mentioned in the error message, so what traits are implemented by it?
impl<F, T> Predicate<T> for FnPredicate<F, T>
where
F: Fn(&T) -> bool,
T: ?Sized,
Here it is! You've passed a closure taking &String
, so the T
in this definition is inferred to be String
, i.e. the implemented trait is Predicate<String>
.
Now, if you recall the first part, you'll see that there is no Predicate<String>
there in implementations!
How to resolve this?
I see two possibilities, as for now:
- You can use the second implementation and make your predicate take reference to a byte slice
&[u8]
. I can't test it with the library itself, since it isn't on the playground, but if I make this change just in closure, I immediately get the error:
error[E0277]: can't compare `[u8]` with `str`
--> src/lib.rs:3:15
|
3 | if (x == "You got it right!" || x == "You got it wrong!") {
| ^^ no implementation for `[u8] == str`
|
= help: the trait `std::cmp::PartialEq<str>` is not implemented for `[u8]`
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&str>` for `&[u8]`
Fortunately, this is fairly easily fixed by changing string literals to byte strings (playground):
let _ = |x: &[u8]| {
x == b"You got it right!" || x == b"You got it wrong!"
};
Note that I also took advantage of Clippy hints to simplify the code in question (on playground it is under Tools button on the right side).
Now, if you pass this closure into predicate::function
, all should work fine.
- Another way is to use the first implementation - you can see that
Predicate<str>
, i.e. function predicate receiving &str
, is also supported, although in a bit more complex way. But for now this doesn't seem to be a problem, since the trait is implemented anyway - that's just one internal layer of indirection, but this is not your problem (assert_cmd
crate should handle this itself). This code, in particular, compiles well:
use assert_cmd::{assert::OutputAssertExt, cargo::CommandCargoExt};
use predicates::prelude::*;
use std::process::Command;
fn main() {
let hazard_predicate =
predicate::function(|x: &str| x == "You got it right!" || x == "You got it wrong!");
let mut cmd = Command::cargo_bin("rust-starter").expect("Calling binary failed");
cmd.arg("hazard").assert().stdout(hazard_predicate);
}
Side note
There is a long-standing question here describing why this is bad to have the functions require &String
(or &Vec
, or &Box
- a reference to the owned container, it is). In short - you can replace &String
by &str
, and this will not be a restriction. Of course, library authors know that too and usually force you to have the most general way, where you have to work with the least indirection possible.