use simulacrum_shared::Validator;
use std::marker::PhantomData;
use super::{ExpectationId, MethodName};
use super::expectation::Expectation;
use super::constraint::stock::times::Times;
use super::constraint::stock::params::Params;
use super::store::ExpectationStore;
pub(crate) struct MethodTypes<I, O> {
pub(crate) input: PhantomData<I>,
pub(crate) output: PhantomData<O>
}
impl<I, O> MethodTypes<I, O> {
pub(crate) fn new() -> Self {
MethodTypes {
input: PhantomData,
output: PhantomData
}
}
}
pub(crate) struct MethodSig<I, O> {
pub(crate) name: MethodName,
pub(crate) _types: MethodTypes<I, O>
}
#[must_use]
pub struct Method<'a, I, O> {
store: &'a mut ExpectationStore,
sig: MethodSig<I, O>,
}
impl<'a, I, O> Method<'a, I, O> where
I: 'static,
O: 'static
{
pub(crate) fn new(store: &'a mut ExpectationStore, name: MethodName) -> Self {
if store.has_expectation_for_method_in_current_era(name) {
panic!("Only one expectation can be set for method '{}' per era - use .then() to create a new era before adding another expectation.", name);
}
let types = MethodTypes {
input: PhantomData,
output: PhantomData
};
let sig = MethodSig {
name,
_types: types
};
Self {
store,
sig
}
}
pub fn called_never(self) -> TrackedMethod<'a, I, O> {
self.called_times(0)
}
pub fn called_once(self) -> TrackedMethod<'a, I, O> {
self.called_times(1)
}
pub fn called_times(self, calls: i64) -> TrackedMethod<'a, I, O> {
let mut exp: Expectation<I, O> = Expectation::new(self.sig.name);
exp.constrain(Times::new(calls));
let id = self.store.add(exp);
TrackedMethod {
id,
method: self
}
}
pub fn called_any(self) -> TrackedMethod<'a, I, O> {
let exp: Expectation<I, O> = Expectation::new(self.sig.name);
let id = self.store.add(exp);
TrackedMethod {
id,
method: self
}
}
}
pub struct TrackedMethod<'a, I, O> {
id: ExpectationId,
method: Method<'a, I, O>
}
impl<'a, I, O> TrackedMethod<'a, I, O> where
I: 'static,
O: 'static
{
pub fn with<V>(self, validator: V) -> Self where
V: Validator<I> + 'static
{
let constraint = Params::new(validator);
self.method.store.get_mut::<I, O>(self.id).constrain(constraint);
self
}
pub fn modifying<F>(self, modification_behavior: F) -> Self where
F: 'static + FnMut(&mut I)
{
self.method.store.get_mut::<I, O>(self.id).set_modification(modification_behavior);
self
}
pub fn returning<F>(self, result_behavior: F) -> Self where
F: 'static + FnMut(&I) -> O
{
self.method.store.get_mut::<I, O>(self.id).set_return(result_behavior);
self
}
}