[][src]Struct faux::When

pub struct When<'q, I, O> { /* fields omitted */ }

Stores who and what to mock, how many times to mock it, and provides methods to mock the method both safely and unsafely.

The methods provided for mocking expect an FnMut to be passed in. This means that data may not be moved to the closure, but rather only borrowed, or mutably borrowed. If you need a way to pass a closure with data moved into it, and that mock only needs to be activated once, you may call once to get a handle to a WhenOnce.

See when! for how to get a instance of this struct.

Methods

impl<'q, I, O> When<'q, I, O>[src]

pub unsafe fn then(self, mock: impl FnMut(I) -> O + Send)[src]

Mocks the method stored in the When with the given closure for the saved instance. This mock has no restrictions on the lifetimes for the inputs, outputs, nor the mocked function itself for maximum flexibility. While this method is "type" safe for the types in the mocked method, it is not lifetime safe. See safety.

The input for the given closure is a tuple of all its non-receiver parameters (e.g., &mut self, or self: Rc<Self>).

By default, this mock will be active for all future calls to this method. If you wish to limit the number of calls that are doable to this mocked method, you may use times prior to calling for this method.

Usage

#[faux::create]
pub struct Foo {}

#[faux::methods]
impl Foo {
    pub fn no_args(&mut self) -> &i32 {
      /* implementation code */
    }

    pub fn single_arg(&self, a: u8) -> Vec<i8> {
      /* implementation code */
    }

    pub fn multi_args(self, a: &i32, b: i8) -> u32 {
      /* implementation code */
    }
}

fn main() {
  let mut mock = Foo::faux();

  // the output can be a reference to the environment
  // but this can be *very* dangerous so be careful
  // note that the closure still has an argument, it is just an empty tuple
  let x = 5;
  unsafe { faux::when!(mock.no_args).then(|_empty: ()| &x) }
  assert_eq!(*mock.no_args(), 5);

  // unit tuples do not need parentheses
  unsafe { faux::when!(mock.single_arg).then(|input| vec![input as i8]) }
  assert_eq!(mock.single_arg(8), vec![8]);
  // mock may be activated multiple times
  assert_eq!(mock.single_arg(8), vec![8]);
  assert_eq!(mock.single_arg(8), vec![8]);

  // inputs can be references
  unsafe { faux::when!(mock.multi_args).then(|(&a, b)| a as u32 + b as u32) }
  assert_eq!(mock.multi_args(&5, 23), 28)
}

Safety

This function effectively erases the lifetime relationships of the inputs and outputs. It is the user's responsability to not pass a mock that would capture a variable that would be used after it has been deallocated.

Another way in which this function is unsafe is if the output of this function has a logical lifetime link to the input. At the moment the mock gets called, that link would be erased which could create multiple mutable references to the same object.

Example:

#[faux::create]
pub struct Foo {}

#[faux::methods]
impl Foo {
    pub fn out_ref(&self, a : &mut i32) -> &mut i32 {
      /* implementation code */
    }
}

fn main() {
  let mut mock = Foo::faux();
  // set up the mock such that the output is the same reference as the input
  unsafe { faux::when!(mock.out_ref).then(|i| i) }

  let mut x = 5;
  // y is now a mutable reference back x
  // but there is no compile-time link between the two
  let y = mock.out_ref(&mut x);

  // We can check that they are both the same value
  assert_eq!(*y, 5);
  assert_eq!(x, 5);

  // x now changes y. This is UB and is not allowed in safe Rust!
  x += 1;
  assert_eq!(x, 6);
  assert_eq!(*y, 6);

  // and if we change y then x also gets changed
  *y += 1;
  assert_eq!(x, 7);
  assert_eq!(*y, 7);
}

pub fn safe_then(self, mock: impl FnMut(I) -> O + 'static + Send) where
    I: 'static,
    O: 'static, 
[src]

Mocks the method stored in the When with the given closure for the saved instance. This mock is restricted only to static inputs, outputs, and closures. While this is very restrictive it allows for a purely safe interface. See then for the unsafe version.

The input for the given closure is a tuple of all its non-receiver parameters (e.g., &mut self, or self: Rc<Self>).

By default, this mock will be active for all future calls to this method. If you wish to limit the number of calls that are doable to this mocked method, you may use [times] prior to calling for this method.

Usage

#[faux::create]
pub struct Foo {}

#[faux::methods]
impl Foo {
    pub fn no_args(&mut self) -> i32 {
      /* implementation code */
    }

    pub fn single_arg(&self, a: u8) -> Vec<i8> {
      /* implementation code */
    }

    pub fn multi_args(self, a: &i32, b: i8) -> u32 {
      /* implementation code */
    }
}

fn main() {
  let mut mock = Foo::faux();

  // closure still has an argument, it is just an empty tuple
  faux::when!(mock.no_args).safe_then(|_empty: ()| 5);
  assert_eq!(mock.no_args(), 5);

  // unit tuples do not need parentheses
  faux::when!(mock.single_arg).safe_then(|input| vec![input as i8]);
  assert_eq!(mock.single_arg(8), vec![8]);
  // mock is active for an infinite number of times
  assert_eq!(mock.single_arg(8), vec![8]);
  assert_eq!(mock.single_arg(8), vec![8]);
  assert_eq!(mock.single_arg(8), vec![8]);

  // one of the arguments for `multi_args` is not a static type
  // so the following line would not compile
  // faux::when!(mock.multi_args).safe_then(|(_, _)| 5);
}

pub fn times(self, times: usize) -> Self[src]

Limits the number of times a mock is active. Any future call past that will result in a panic, causing your test to fail.

Usage

#[faux::create]
pub struct Foo {}

#[faux::methods]
impl Foo {
    pub fn single_arg(&self, a: u8) -> Vec<i8> {
      /* implementation code */
    }
}

fn main() {
  let mut mock = Foo::faux();

  // can be called 3 times
  faux::when!(mock.single_arg).times(3).safe_then(|input| vec![input as i8]);
  assert_eq!(mock.single_arg(8), vec![8]);
  assert_eq!(mock.single_arg(8), vec![8]);
  assert_eq!(mock.single_arg(8), vec![8]);
  assert_eq!(mock.single_arg(8), vec![8]); //panics on its 4th call
}

pub fn once(self) -> WhenOnce<'q, I, O>[src]

Returns a handle to a WhenOnce. Useful when the closure you wish to pass to this mock needs to move data rather than borrow it. It, however, makes your mocked method only callable once.

#[faux::create]
pub struct Foo {}

#[faux::methods]
impl Foo {
    pub fn single_arg(&self, a: u8) -> Vec<i8> {
      /* implementation code */
    }
}

fn main() {
  let mut mock = Foo::faux();

  let vec = vec![25];
  faux::when!(mock.single_arg).once().safe_then(|_| vec); //moves vec to the closure
  assert_eq!(mock.single_arg(8), vec![25]);

  mock.single_arg(8); //panics on its 2nd call
}

Auto Trait Implementations

impl<'q, I, O> !RefUnwindSafe for When<'q, I, O>

impl<'q, I, O> !Send for When<'q, I, O>

impl<'q, I, O> !Sync for When<'q, I, O>

impl<'q, I, O> Unpin for When<'q, I, O>

impl<'q, I, O> !UnwindSafe for When<'q, I, O>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.