use std::fmt;
use std::fmt::{Debug, Formatter};
use std::sync::{Arc, RwLock};
type OptionalRef<T> = Arc<RwLock<Option<T>>>;
#[derive(Clone)]
pub struct Mock<C, R>
where
C: Clone,
R: Clone,
{
return_value: Arc<RwLock<R>>,
mock_fn: OptionalRef<fn(C) -> R>,
mock_closure: OptionalRef<Box<Fn(C) -> R + Send + Sync>>,
calls: Arc<RwLock<Vec<C>>>,
}
impl<C, R> Mock<C, R>
where
C: Clone,
R: Clone,
{
pub fn new<T: Into<R>>(return_value: T) -> Self {
Mock {
return_value: Arc::new(RwLock::new(return_value.into())),
mock_fn: Arc::new(RwLock::new(None)),
mock_closure: Arc::new(RwLock::new(None)),
calls: Arc::new(RwLock::new(vec![])),
}
}
pub fn call(&self, args: C) -> R {
self.calls.write().unwrap().push(args.clone());
if let Some(ref mock_fn) = *self.mock_fn.read().unwrap() {
return mock_fn(args);
}
if let Some(ref mock_closure) = *self.mock_closure.read().unwrap() {
return mock_closure(args);
}
self.return_value.read().unwrap().clone()
}
pub fn return_value<T: Into<R>>(&self, return_value: T) {
let mut value = self.return_value.write().unwrap();
*value = return_value.into()
}
pub fn use_fn(&self, mock_fn: fn(C) -> R) {
let mut closure_value = self.mock_closure.write().unwrap();
*closure_value = None;
let mut fn_value = self.mock_fn.write().unwrap();
*fn_value = Some(mock_fn)
}
pub fn use_closure(&self, mock_fn: Box<Fn(C) -> R + Send + Sync>) {
let mut fn_value = self.mock_fn.write().unwrap();
*fn_value = None;
let mut closure_value = self.mock_closure.write().unwrap();
*closure_value = Some(mock_fn)
}
pub fn called(&self) -> bool {
let calls = (*self.calls).read().unwrap();
!calls.is_empty()
}
pub fn num_calls(&self) -> usize {
self.calls.read().unwrap().len()
}
pub fn calls(&self) -> Vec<C> {
self.calls.read().unwrap().clone()
}
pub fn reset_calls(&self) {
self.calls.write().unwrap().clear()
}
}
impl<C, R> Default for Mock<C, R>
where
C: Clone,
R: Clone + Default,
{
fn default() -> Self {
Self::new(R::default())
}
}
impl<C, R> Mock<C, R>
where
C: Clone + PartialEq,
R: Clone,
{
pub fn called_with<T: Into<C>>(&self, args: T) -> bool {
self.calls.read().unwrap().contains(&args.into())
}
}
impl<C, S> Mock<C, Option<S>>
where
C: Clone,
S: Clone,
{
pub fn return_some<T: Into<S>>(&self, return_value: T) {
self.return_value(Some(return_value.into()))
}
pub fn return_none(&self) {
self.return_value(None)
}
}
impl<C, O, E> Mock<C, Result<O, E>>
where
C: Clone,
O: Clone,
E: Clone,
{
pub fn return_ok<T: Into<O>>(&self, return_value: T) {
self.return_value(Ok(return_value.into()))
}
pub fn return_err<T: Into<E>>(&self, return_value: T) {
self.return_value(Err(return_value.into()))
}
}
impl<C, R> Debug for Mock<C, R>
where
C: Clone + Debug,
R: Clone + Debug,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("Mock")
.field("return_value", &self.return_value)
.field("calls", &self.calls)
.finish()
}
}