I know what the error means, but I can't fix it. I'm using mockers
to test my work and I got stuck when trying to verify the struct parameter which was given to a mocked trait's function. The simplified code:
#[cfg(test)]
extern crate mockers;
#[cfg(test)]
extern crate mockers_derive;
#[cfg(test)]
use mockers_derive::mocked;
#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
pub struct Thing {
pub key: String,
pub class: String,
}
#[cfg_attr(test, mocked)]
pub trait DaoTrait {
fn get(&self, thing: &Thing) -> String;
}
struct DataService {
dao: Box<DaoTrait>,
}
impl DataService {
pub fn get(&self, thing: &Thing) -> String {
self.dao.get(thing)
}
}
#[cfg(test)]
mod test {
use super::*;
use mockers::matchers::eq;
use mockers::Scenario;
#[test]
fn my_test() {
use mockers::matchers::check;
let scenario = Scenario::new();
let mut dao = scenario.create_mock_for::<DaoTrait>();
let thing = Thing {
key: "my test".to_string(),
class: "for test".to_string(),
};
scenario.expect(
dao.get_call(check(|t: &Thing| t.to_owned() == thing))
.and_return("hello".to_string()),
);
let testee = DataService { dao: Box::new(dao) };
let rtn = testee.get(&thing);
assert_eq!(rtn, "hello");
}
}
I got the errors:
warning: unused import: `mockers::matchers::eq`
--> src/main.rs:33:9
|
33 | use mockers::matchers::eq;
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unused_imports)] on by default
error[E0277]: can't compare `&Thing` with `Thing`
--> src/main.rs:47:57
|
47 | dao.get_call(check(|t: &Thing| t.to_owned() == thing))
| ^^ no implementation for `&Thing == Thing`
|
= help: the trait `std::cmp::PartialEq<Thing>` is not implemented for `&Thing`
error[E0277]: the trait bound `mockers::matchers::BoolFnMatchArg<Thing, [closure@src/main.rs:47:32: 47:65 thing:_]>: mockers::MatchArg<&Thing>` is not satisfied
--> src/main.rs:47:17
|
47 | dao.get_call(check(|t: &Thing| t.to_owned() == thing))
| ^^^^^^^^ the trait `mockers::MatchArg<&Thing>` is not implemented for `mockers::matchers::BoolFnMatchArg<Thing, [closure@src/main.rs:47:32: 47:65 thing:_]>`
|
= help: the following implementations were found:
<mockers::matchers::BoolFnMatchArg<T, F> as mockers::MatchArg<T>>
I viewed check
's source code :
pub fn check<T, F: Fn(&T) -> bool>(f: F) -> BoolFnMatchArg<T, F> {
BoolFnMatchArg { func: f, _phantom: PhantomData }
}
I think the closure |t: &Thing| t.to_owned() == thing
I had given is right. I also tried the following closures, but none of them worked.
|t: &Thing| t == &thing
|t: &Thing| *t == thing
|t: Thing| t == thing
The Cargo.toml:
[dev-dependencies]
mockers = "0.12.1"
mockers_derive = "0.12.1"
You cannot compare a
Thing
to a&Thing
using the default derivation ofPartialEq
:To fix that error, you need to do one of two things:
Match the reference level:
t_val == *t_ref
&t_val == t_ref
Implement equality for a mismatched number of references:
However, none of that solves your actual problem. You've misunderstood how the mockers library works; your closure is taking the wrong level of reference, and it needs to take ownership of the value to compare:
The first thing (pun not intended) to notice is that
t.to_owned()
produces a&Thing
, not aThing
as you might have expected. That's becauseThing
doesn't implementClone
, and therefore it doesn't implementToOwned
either (because there is a blanket impl that implementsToOwned
for allClone
types), which provides theto_owned
method. But then why does the call still work? Because references implementClone
, so&Thing
implementsToOwned
! This givesto_owned
this signature:You can fix this by deriving
Clone
forThing
.However, you don't need to clone the
Thing
in order to compare it. You can instead compare two references toThing
(e.g. by writing|t: &Thing| t == &thing
).PartialEq::eq
(which the==
operator translates to) takes its arguments by reference, and references implementPartialEq
by peeling off a layer of references (i.e. they don't compare the pointer values, unlike raw pointer types).