diff options
Diffstat (limited to 'subplotlib/src/scenario.rs')
-rw-r--r-- | subplotlib/src/scenario.rs | 75 |
1 files changed, 74 insertions, 1 deletions
diff --git a/subplotlib/src/scenario.rs b/subplotlib/src/scenario.rs index 7cebb31..7a78ae5 100644 --- a/subplotlib/src/scenario.rs +++ b/subplotlib/src/scenario.rs @@ -4,6 +4,8 @@ //! Instead instances of it are constructed in the generated test functions and //! will be run automatically. +use core::fmt; +use std::fmt::Debug; use std::{cell::RefCell, marker::PhantomData, sync::Mutex}; use state::Container; @@ -18,7 +20,7 @@ use crate::types::{StepError, StepResult}; /// be aware that they won't always be called on scenario start and they will /// not be caught up the first time they are invoked for a step, simply expected /// to get on with life from their first use. -pub trait ContextElement: Default + Send + 'static { +pub trait ContextElement: Debug + Default + Send + 'static { /// A new context element was created. /// /// In order to permit elements which for example work on disk, this @@ -122,6 +124,9 @@ trait ScenarioContextHookKind { /// Leave a step fn step_stops(&self, contexts: &ScenarioContext) -> StepResult; + + /// Produce your debug output + fn debug(&self, contexts: &ScenarioContext, dc: &mut DebuggedContext, alternate: bool); } impl<C> ScenarioContextHookKind for ScenarioContextHook<C> @@ -143,6 +148,10 @@ where fn step_stops(&self, contexts: &ScenarioContext) -> StepResult { contexts.with_mut(|c: &mut C| c.step_stops(), true) } + + fn debug(&self, contexts: &ScenarioContext, dc: &mut DebuggedContext, alternate: bool) { + contexts.with_generic(|c: &C| dc.add(c, alternate)); + } } /// A container for all scenario contexts @@ -154,6 +163,54 @@ pub struct ScenarioContext { hooks: RefCell<Vec<Box<dyn ScenarioContextHookKind>>>, } +#[derive(Default)] +struct DebuggedContext { + body: Vec<String>, +} + +impl DebuggedContext { + fn add<C>(&mut self, obj: &C, alternate: bool) + where + C: Debug, + { + let body = if alternate { + format!("{:#?}", obj) + } else { + format!("{:?}", obj) + }; + self.body.push(body); + } +} + +struct DebugContextString<'a>(&'a str); + +impl<'a> Debug for DebugContextString<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.0) + } +} + +impl Debug for DebuggedContext { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.body.iter().map(|s| DebugContextString(s))) + .finish() + } +} + +impl Debug for ScenarioContext { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut contexts = DebuggedContext::default(); + for hook in self.hooks.borrow().iter() { + hook.debug(self, &mut contexts, f.alternate()); + } + f.debug_struct("ScenarioContext") + .field("title", &self.title) + .field("contexts", &contexts) + .finish() + } +} + impl ScenarioContext { fn new(title: &str) -> Self { Self { @@ -186,6 +243,22 @@ impl ScenarioContext { } } + fn with_generic<C, F>(&self, func: F) + where + F: FnOnce(&C), + C: ContextElement, + { + let sci: &ScenarioContextItem<C> = self + .inner + .try_get() + .expect("Scenario Context item not initialised"); + let lock = match sci.0.lock() { + Ok(lock) => lock, + Err(pe) => pe.into_inner(), + }; + func(&lock) + } + /// With the extracted immutable context, run the function f. pub fn with<C, F, R>(&self, func: F, defuse_poison: bool) -> Result<R, StepError> where |