Struct faux::When[][src]

pub struct When<'q, R, I, O, M: InvocationMatcher<I>> { /* fields omitted */ }
Expand description

Provides methods to stub the implementation or return value of the mocked method.

Created using when!.

By default, methods are mocked for all invocations. Use when! for an ergonomic way to set argument matchers. For more features, use with_args.

By default, all methods are mocked indefinitely. Thus, any stubbed values needs to be cloneable and any stubbed implementation cannot consume variables. Use the times and once methods to override these defaults.

Do NOT rely on the signature of When. While changing the methods of When will be considered a breaking change, changing the generics within When will not.

Implementations

Sets the return value of the mocked method.

Requires the value to be static. For a more lax but unsafe alternative, use then_unchecked_return.

The returned value will be cloned on each invocation of the mock. Using this method to return another mock instance will fail unless that mock instance has its clone method already mocked.

Examples

#[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);
  // mock activates multiple times
  assert_eq!(mock.multi_args(&2, 3), 5);
  assert_eq!(mock.multi_args(&2, 3), 5);
}

Sets the implementation of the mocked method to the provided closure.

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

The provided closure can only capture static variables and it must be mocking a method with static output. For a more lax but unsafe alternative, use then_unchecked.

Examples

#[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 */
    }

    pub fn out_ref(&self) -> &u32 {
      /* implementation code */
    }
}

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

  // method with no params
  faux::when!(mock.no_args).then(|_| 5);
  assert_eq!(mock.no_args(), 5);

  // method with a single param
  faux::when!(mock.single_arg).then(|input| vec![input as i8]);
  assert_eq!(mock.single_arg(8), vec![8]);

  // method with multiple params - some can be references
  faux::when!(mock.multi_args).then(|(&a, _)| a as u32);
  assert_eq!(mock.multi_args(&5, 2), 5);

  // cannot mock methods that return references
  // let x = 5;
  // faux::when!(mock.out_ref).then(|_| &x);
}

Analog of then_return that allows stubbing non-static return values.

Examples

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

  let x = 5;
  unsafe { faux::when!(mock.multi_args).then_unchecked_return(&x) }
  assert_eq!(*mock.multi_args(&2, 3), x);
}

Safety

The lifetime of the returned object is not checked and can cause memory safety issues if used incorrectly.

If the owner of the borrowed data is dropped while the captured reference is still accessible, a use-after-free violation will be triggered.

This method can also cause aliasing issues where multiple mutable references are held for the same object.

Examples

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

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

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

  let x = 5;
  unsafe { faux::when!(mock.out_ref).then_unchecked_return(&x) }
  std::mem::drop(x);
  // assert_eq!(*mock.ref_return(), 5); // <~~ UB: use after free
}

Analog of then that allows stubbing implementations with non-static closures.

Examples

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

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

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

  // the output can be a reference to the environment
  // but this can be *very* dangerous
  let x = 5;
  unsafe { faux::when!(mock.out_ref).then_unchecked(|_| &x) }
  assert_eq!(*mock.out_ref(), x);
}

Safety

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

If the mocked method is called after its captured variables are dropped then a use-after-free violation will be triggered.

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

Examples

#[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 and input references are the same
  unsafe { faux::when!(mock.out_ref).then_unchecked(|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);

  // x and y are pointing to the same data!
  assert_eq!(*y, 5);
  assert_eq!(x, 5);

  // changes in x are reflected in y and vice versa
  // this is UB and is not allowed in safe Rust!
  x += 1;
  assert_eq!(x, 6);
  assert_eq!(*y, 6);
}

Limits the number of calls for which a mock is active.

Calls past the limit will result in a panic.

Examples

#[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 calls
  faux::when!(mock.single_arg)
      .times(5)
      .then(|input| vec![input as i8]);

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

Panics

Panics if the mock is called more times than specified.

#[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 calls
  faux::when!(mock.single_arg)
      .times(5)
      .then(|input| vec![input as i8]);

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

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

Panics if the mock is called more than once.

Examples

#[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().then(|_| vec);
  assert_eq!(mock.single_arg(8), vec![25]);
}

Panics

Panics if the mock is called more than 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().then(|_| vec);
  assert_eq!(mock.single_arg(8), vec![25]);
  //panics on its second call
  mock.single_arg(8);
}

Specifies a matcher for the invocation.

This lets you pass matchers for each method argument.

See when! for an ergonomic way to pass the matcher.

If all arguments implement Debug, a tuple of ArgMatchers can be provided where each ArgMatcher matches an individual argument.

If the method only has a single argument, use a tuple of a single element: (ArgMatcher,)

For more complex cases, you may pass a custom InvocationMatcher.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Performs the conversion.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.