Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support DerefMut for mocks #191

Closed
bradforj287 opened this issue Aug 31, 2020 · 3 comments
Closed

Support DerefMut for mocks #191

bradforj287 opened this issue Aug 31, 2020 · 3 comments

Comments

@bradforj287
Copy link

I ran into a bit of a snag testing code involving a lot of smart pointers.

I wanted to do something like this:

  1. create the mock in an Arc
  2. set some expectations on the mock
  3. pass a pointer to the mock to the code under test.
  4. trigger the code utilizing the mock
  5. checkpoint()
  6. repeat, go back to step 2

I couldn't accomplish this because this code won't compile:
This code:

    let mut mock = Arc::new(MockMyService::new());
    mock.expect_get_current()
        .times(1)
        .returning(|input| {
        input * input
    });

fails with a compiler error:

error[E0596]: cannot borrow data in an `Arc` as mutable
  --> src/main.rs:50:5
   |
50 |     mock.expect_get_current()
   |     ^^^^ cannot borrow as mutable
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::sync::Arc<MockMyService>`

I'm wondering if it makes sense to support DerefMut to make testing with smart pointers easier?

@asomers
Copy link
Owner

asomers commented Aug 31, 2020

No. The problem here is that setting expectations requires mutable access to the mock. But Arc does not provide interior mutability. What you want is either to use an Arc<Mutex<MockMyService>>, or else set the expectations before you Arc it, like this:

let mut mock = MockMyService::new();
mock.expect_get_current()
        .times(1)
        .returning(|input| {
        input * input
    });
let arcmock = Arc::new(mock);

@asomers asomers closed this as completed Aug 31, 2020
@bradforj287
Copy link
Author

Yup, setting expectations before mocking is the workaround i went with. There is another workaround involving unsafe code. Example:

#![feature(get_mut_unchecked)]
use std::sync::Arc;

fn main() {

    let mut v: Vec<i32> = Vec::new();
    v.push(1);

    println!("data: {:?}", v);
    let a = Arc::new(v);

    unsafe {
        let mut aa = a.clone();
        let mut d = Arc::get_mut_unchecked(&mut aa);
        d.push(55);
    }
    println!("data: {:?}", a);
}

@YarekTyshchenko
Copy link

After some searching I found a solution to this: #327 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants