[][src]Struct faux::When

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

Stores who to mock, what to mock, and how many times to mock it.

Created using when!.

By default all methods are mocked indefinitely and the mock closures may not consume captured variables. See the times and once methods to override these default.

Implementations

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

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

Saves a mock without any lifetime checks.

The provided mock has no restrictions on the lifetimes of 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.

The input for the given closure is a tuple of all its non-receiver parameters.

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
  let x = 5;
  // methods with no arguments have mocks with empty tuples
  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

The lifetimes of the inputs, outputs, and captured variables are not checked. While this gives the caller maximum flexibility when mocking it also not memory safe when used incorrectly.

Captured variables could be used after-freed if the mock was called after them being dropped. This would create undefined behavior.

Relationships between inputs, outputs, and captured variable lifetimes are lost. This allows for easy violations of Rust's aliasing checks, creating undefined behavior.

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();
  // the output is the same reference as the input
  // the lifetimes of the input and output are thus linked
  unsafe { faux::when!(mock.out_ref).then(|i| i) }

  let mut x = 5;
  // y (the output) is a mutable reference back to x (the input)
  // 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);

  // changes in x are reflected in 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 then_do(self, mock: impl FnMut() -> O + 'static + Send) where
    O: 'static, 
[src]

Saves a mock that does not allow a view into its inputs.

Because the mock does not receive any inputs, it allows for safe mocking of methods that have non-static inputs. The output and the mock itself must still be a static type.

Usage

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

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

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

  // mock has no inputs
  faux::when!(mock.multi_args).then_do(|| 5);
  assert_eq!(mock.multi_args(&3, 4), 5);
  // mock activates multiple times
  assert_eq!(mock.multi_args(&3, 4), 5);
}

pub fn then_return(self, mock: O) where
    O: 'static + Send + Clone
[src]

Saves an object as the return value of the mock.

Requires the object to be cloneable and static.

Usage

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

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

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

  faux::when!(mock.multi_args).then_return(5);
  assert_eq!(mock.multi_args(&2, 3), 5);
  // mock activates multiple times
  assert_eq!(mock.multi_args(&2, 3), 5);
}

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

Saves a mock where all the mock lifetimes are checked.

The provided mock must be static, and it must be mocking a method with static inputs and ouputs. While this is very restrictive it allows for a purely safe interface.

The input for the given closure is a tuple of all its non-receiver parameters.

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();

  // 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.

Calls past the limit results in a panic.

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();

  // limit to 5 times
  faux::when!(mock.single_arg)
      .times(5)
      .safe_then(|input| vec![input as i8]);

  // can be called 5 times safely
  for _ in 0..5 {
    assert_eq!(mock.single_arg(8), vec![8]);
  }
}

Panics

This example panics
#[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();

  // limit to 5 times
  faux::when!(mock.single_arg)
      .times(5)
      .safe_then(|input| vec![input as i8]);

  // panics on the 6th call
  for _ in 0..6 {
    assert_eq!(mock.single_arg(8), vec![8]);
  }
}

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

Limits mock to one call, allowing mocks to consume captured variables.

Panics if the mock is called more than once.

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();

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

Panics

This example panics
#[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);
  assert_eq!(mock.single_arg(8), vec![25]);
  //panics on its 2nd call
  mock.single_arg(8);
}

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.