diff options
-rw-r--r-- | subplotlib/helpers/subplotlib_context.rs | 2 | ||||
-rw-r--r-- | subplotlib/src/file.rs | 2 | ||||
-rw-r--r-- | subplotlib/src/prelude.rs | 6 | ||||
-rw-r--r-- | subplotlib/src/scenario.rs | 75 | ||||
-rw-r--r-- | subplotlib/src/steplibrary/datadir.rs | 14 | ||||
-rw-r--r-- | subplotlib/src/steplibrary/files.rs | 2 | ||||
-rw-r--r-- | subplotlib/src/steplibrary/runcmd.rs | 13 | ||||
-rw-r--r-- | subplotlib/subplot-rust-support.rs | 2 |
8 files changed, 108 insertions, 8 deletions
diff --git a/subplotlib/helpers/subplotlib_context.rs b/subplotlib/helpers/subplotlib_context.rs index c662c98..d5ea7cc 100644 --- a/subplotlib/helpers/subplotlib_context.rs +++ b/subplotlib/helpers/subplotlib_context.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -#[derive(Default)] +#[derive(Debug, Default)] struct Context { counter: usize, files: HashMap<String, SubplotDataFile>, diff --git a/subplotlib/src/file.rs b/subplotlib/src/file.rs index b683c39..84f3495 100644 --- a/subplotlib/src/file.rs +++ b/subplotlib/src/file.rs @@ -18,7 +18,7 @@ use base64::decode; /// /// ```rust /// # use subplotlib::prelude::*; -/// # #[derive(Default)] +/// # #[derive(Debug, Default)] /// # struct Context {} /// # impl ContextElement for Context {} /// #[step] diff --git a/subplotlib/src/prelude.rs b/subplotlib/src/prelude.rs index 4f5b781..e0ac627 100644 --- a/subplotlib/src/prelude.rs +++ b/subplotlib/src/prelude.rs @@ -72,7 +72,7 @@ pub use lazy_static::lazy_static; /// /// ```rust /// # use subplotlib::prelude::*; -/// # #[derive(Default)] struct SomeContextType; +/// # #[derive(Debug, Default)] struct SomeContextType; /// # impl ContextElement for SomeContextType {} /// #[step] /// fn my_step_function(context: &mut SomeContextType, arg1: &str, arg2: &str) @@ -99,8 +99,8 @@ pub use lazy_static::lazy_static; /// /// ```rust /// # use subplotlib::prelude::*; -/// # #[derive(Default)] struct ContextA; -/// # #[derive(Default)] struct ContextB; +/// # #[derive(Debug, Default)] struct ContextA; +/// # #[derive(Debug, Default)] struct ContextB; /// # impl ContextElement for ContextA {} /// # impl ContextElement for ContextB {} /// # impl ContextA { fn get_thingy(&self) -> Result<usize, StepError> { Ok(0) } } 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 diff --git a/subplotlib/src/steplibrary/datadir.rs b/subplotlib/src/steplibrary/datadir.rs index e6eadbe..5a344df 100644 --- a/subplotlib/src/steplibrary/datadir.rs +++ b/subplotlib/src/steplibrary/datadir.rs @@ -5,6 +5,7 @@ //! If you want to create files, run commands, etc. from your scenarios, you //! will likely be using them from within the datadir. +use std::fmt::Debug; use std::fs::{File, OpenOptions}; use std::path::{Component, Path, PathBuf}; @@ -23,10 +24,23 @@ pub struct Datadir { inner: Option<DatadirInner>, } +#[derive(Debug)] pub struct DatadirInner { base: tempfile::TempDir, } +impl Debug for Datadir { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.inner { + Some(inner) => (inner as &dyn Debug).fmt(f), + None => f + .debug_struct("Datadir") + .field("inner", &self.inner) + .finish(), + } + } +} + impl ContextElement for Datadir { fn created(&mut self, scenario: &Scenario) { assert!(self.inner.is_none()); diff --git a/subplotlib/src/steplibrary/files.rs b/subplotlib/src/steplibrary/files.rs index b94155f..991cd88 100644 --- a/subplotlib/src/steplibrary/files.rs +++ b/subplotlib/src/steplibrary/files.rs @@ -18,7 +18,7 @@ pub use crate::prelude::*; pub use super::datadir::Datadir; -#[derive(Default)] +#[derive(Debug, Default)] /// Context data for the `files` step library /// /// This context contains a mapping from filename to metadata so that diff --git a/subplotlib/src/steplibrary/runcmd.rs b/subplotlib/src/steplibrary/runcmd.rs index fc93b7e..b90f8b7 100644 --- a/subplotlib/src/steplibrary/runcmd.rs +++ b/subplotlib/src/steplibrary/runcmd.rs @@ -8,6 +8,7 @@ pub use crate::prelude::*; use std::collections::HashMap; use std::env::{self, JoinPathsError}; use std::ffi::{OsStr, OsString}; +use std::fmt::Debug; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -27,6 +28,18 @@ pub struct Runcmd { stderr: Vec<u8>, } +impl Debug for Runcmd { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Runcmd") + .field("env", &self.env) + .field("paths", &self.paths) + .field("exitcode", &self.exitcode) + .field("stdout", &String::from_utf8_lossy(&self.stdout)) + .field("stderr", &String::from_utf8_lossy(&self.stderr)) + .finish() + } +} + // Note, this prefix requires that the injection env vars must have // names which are valid unicode (and ideally ASCII) const ENV_INJECTION_PREFIX: &str = "SUBPLOT_ENV_"; diff --git a/subplotlib/subplot-rust-support.rs b/subplotlib/subplot-rust-support.rs index 60be080..a63ef75 100644 --- a/subplotlib/subplot-rust-support.rs +++ b/subplotlib/subplot-rust-support.rs @@ -7,7 +7,7 @@ use tempfile::TempDir; use std::io::{Read, Seek, SeekFrom}; -#[derive(Default)] +#[derive(Debug, Default)] struct SubplotContext { bin_dir: Option<TempDir>, } |