use handlebox::HandleBox;
use std::cell::RefCell;
use std::sync::Mutex;
use super::{ExpectationId, MethodName};
use super::expectation::{Constraint, Expectation, ExpectationT, ExpectationResult};
use super::method::{MethodSig, MethodTypes};
pub(crate) struct ExpectationStore(Mutex<Inner>);
struct Inner {
current_unverified_era: usize,
eras: Vec<Era>,
expectations: HandleBox<Box<ExpectationT>>
}
type Era = Vec<ExpectationId>;
impl ExpectationStore {
pub fn new() -> Self {
let eras = vec![Era::new()];
ExpectationStore(Mutex::new(Inner {
current_unverified_era: 0,
eras,
expectations: HandleBox::new()
}))
}
pub fn get_mut<I, O>(&self, id: ExpectationId) -> ExpectationEditor<I, O> {
ExpectationEditor {
id,
store: &self,
_types: MethodTypes::new()
}
}
pub(crate) fn has_expectation_for_method_in_current_era(&self, name: MethodName) -> bool {
self.advance_era();
let inner = self.0.lock().unwrap();
for id in inner.eras.last().unwrap() {
if inner.expectations.get(&id).unwrap().name() == name {
return true;
}
}
false
}
pub fn matcher_for<I, O>(&self, name: MethodName) -> ExpectationMatcher<I, O> where
I: 'static,
O: 'static
{
let sig = MethodSig {
name,
_types: MethodTypes::new()
};
self.advance_era();
let inner = self.0.lock().unwrap();
if inner.current_unverified_era < inner.eras.len() {
let mut ids = inner.eras.get(inner.current_unverified_era).unwrap().clone();
ids.retain(|&id| {
inner.expectations.get(&id).unwrap().name() == name
});
ExpectationMatcher {
ids,
sig,
store: &self
}
} else {
ExpectationMatcher {
ids: Vec::new(),
sig,
store: &self
}
}
}
#[allow(unused_must_use)]
pub fn advance_era(&self) {
self.verify();
}
pub fn add<E>(&self, expectation: E) -> ExpectationId where
E: ExpectationT + 'static
{
let mut inner = self.0.lock().unwrap();
let id = inner.expectations.add(Box::new(expectation));
inner.eras.last_mut().unwrap().push(id);
id
}
pub fn new_era(&self) {
let mut inner = self.0.lock().unwrap();
inner.eras.push(Vec::new());
}
pub fn verify(&self) -> ExpectationResult {
let mut status = Ok(());
let mut inner = self.0.lock().unwrap();
let original_unverified_era = inner.current_unverified_era;
'eras: for era_index in original_unverified_era .. inner.eras.len() {
inner.current_unverified_era = era_index;
let era = &inner.eras[era_index];
for id in era.iter() {
let expectation = inner.expectations.get(id).unwrap();
let r = expectation.verify();
if r.is_err() {
status = r;
break 'eras;
}
}
}
status
}
#[allow(dead_code)]
fn exp_count(&self) -> usize {
self.0.lock().unwrap().expectations.map.len()
}
#[allow(dead_code)]
fn era_count(&self) -> usize {
self.0.lock().unwrap().eras.len()
}
}
pub struct ExpectationEditor<'a, I, O> {
id: ExpectationId,
store: &'a ExpectationStore,
_types: MethodTypes<I, O>
}
impl<'a, I, O> ExpectationEditor<'a, I, O> where
I: 'static,
O: 'static
{
pub(crate) fn constrain<C>(&self, constraint: C) where
C: Constraint<I> + 'static
{
self.store.0.lock().unwrap().expectations.get_mut(&self.id).unwrap().as_any().downcast_mut::<Expectation<I, O>>().unwrap().constrain(constraint);
}
pub(crate) fn set_modification<F>(&mut self, modification_behavior: F) where
F: 'static + FnMut(&mut I)
{
self.store.0.lock().unwrap().expectations.get_mut(&self.id).unwrap().as_any().downcast_mut::<Expectation<I, O>>().unwrap().set_modification(modification_behavior);
}
pub(crate) fn set_return<F>(&mut self, return_behavior: F) where
F: 'static + FnMut(&I) -> O
{
self.store.0.lock().unwrap().expectations.get_mut(&self.id).unwrap().as_any().downcast_mut::<Expectation<I, O>>().unwrap().set_return(return_behavior);
}
#[allow(dead_code)]
fn verify(&self) -> ExpectationResult {
self.store.0.lock().unwrap().expectations.get_mut(&self.id).unwrap().verify()
}
}
pub(crate) struct ExpectationMatcher<'a, I, O> {
ids: Vec<ExpectationId>,
sig: MethodSig<I, O>,
store: &'a ExpectationStore
}
impl<'a, I, O> ExpectationMatcher<'a, I, O> where
I: 'static,
O: 'static
{
#[allow(unused_must_use)]
pub fn was_called(self, params: I) -> Self {
let cell = RefCell::new(params);
for id in self.ids.iter() {
self.store.0.lock().unwrap().expectations.get_mut(&id).unwrap().as_any().downcast_mut::<Expectation<I, O>>().unwrap().handle_call(&cell);
}
self
}
#[allow(unused_must_use)]
pub fn was_called_returning(mut self, params: I) -> O {
let cell = RefCell::new(params);
if let Some(id) = self.ids.pop() {
self.store.0.lock().unwrap().expectations.get_mut(&id).unwrap().as_any().downcast_mut::<Expectation<I, O>>().unwrap().handle_call(&cell);
let result = self.store.0.lock().unwrap().expectations.get_mut(&id).unwrap().as_any().downcast_mut::<Expectation<I, O>>().unwrap().return_value_for(&cell);
result
} else {
panic!("Can't return a value for method `{}` with no matching expectations.", self.sig.name);
}
}
#[allow(dead_code)]
fn id_count(&self) -> usize {
self.ids.len()
}
}
#[cfg(test)]
mod store_tests {
use super::*;
use constraint::ConstraintError;
use constraint::stock::always::{AlwaysFail, AlwaysPass};
#[test]
fn test_new() {
let s = ExpectationStore::new();
assert!(s.verify().is_ok(), "Store should be Ok after creation");
assert_eq!(s.era_count(), 1, "Store should have one Era after creation");
assert_eq!(s.exp_count(), 0, "Store should have no Expectations after creation");
}
#[test]
fn test_add() {
let s = ExpectationStore::new();
let e: Expectation<(), ()> = Expectation::new("foo");
s.add(e);
assert_eq!(s.era_count(), 1, "Number of Eras");
assert_eq!(s.exp_count(), 1, "Number of Expectations");
}
#[test]
fn test_new_era() {
let s = ExpectationStore::new();
s.new_era();
assert_eq!(s.era_count(), 2, "Number of Eras after creating a new one");
}
#[test]
fn test_verify_no_expectations() {
let s = ExpectationStore::new();
let r = s.verify();
assert!(r.is_ok());
}
#[test]
fn test_verify_simple_pass() {
let s = ExpectationStore::new();
let mut e: Expectation<(), ()> = Expectation::new("squig");
e.constrain(AlwaysPass);
s.add(e);
let r = s.verify();
assert!(r.is_ok(), "Store should pass");
}
#[test]
fn test_verify_simple_fail() {
let s = ExpectationStore::new();
let mut e: Expectation<(), ()> = Expectation::new("zooks");
e.constrain(AlwaysFail);
s.add(e);
let r = s.verify();
assert!(r.is_err(), "Store should fail");
let r = r.unwrap_err();
assert_eq!(r.method_name, "zooks", "Store error should have the correct method name");
assert_eq!(r.constraint_err, ConstraintError::AlwaysFail, "Store error should contain the correct Constraint error");
}
#[test]
fn test_match() {
let s = ExpectationStore::new();
let mut e: Expectation<(), ()> = Expectation::new("frolf");
e.constrain(AlwaysPass);
s.add(e);
let mut e: Expectation<(), ()> = Expectation::new("star");
e.constrain(AlwaysPass);
s.add(e);
let m = s.matcher_for::<(), ()>("star");
assert_eq!(m.id_count(), 1, "Ids matched should be 1");
}
#[test]
fn test_match_current_era() {
let s = ExpectationStore::new();
let mut e: Expectation<(), ()> = Expectation::new("frob");
e.constrain(AlwaysFail);
s.add(e);
s.new_era();
let mut e: Expectation<(), ()> = Expectation::new("frob");
e.constrain(AlwaysFail);
s.add(e);
let mut e: Expectation<(), ()> = Expectation::new("frob");
e.constrain(AlwaysFail);
s.add(e);
let m = s.matcher_for::<(), ()>("frob");
assert_eq!(m.id_count(), 1, "Ids matched should be 1");
}
#[test]
fn test_match_current_era_passed() {
let s = ExpectationStore::new();
let mut e: Expectation<(), ()> = Expectation::new("buzz");
e.constrain(AlwaysPass);
s.add(e);
s.0.lock().unwrap().current_unverified_era = 1;
let m = s.matcher_for::<(), ()>("buzz");
assert_eq!(m.id_count(), 0, "Ids matched should be 0");
}
}