summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2022-04-02 05:35:58 +0000
committerLars Wirzenius <liw@liw.fi>2022-04-02 05:35:58 +0000
commit962f63413168862fab50da1fe3b6430028277c16 (patch)
treeab8cb27a11df311cd2a1d7acf2300c4d0e8420f0
parent6dfb847facc74e8f05bcd1ba59ab734c319e9f86 (diff)
parent4f2142453c7d25f581dfce761db9a4003355eeca (diff)
downloadsubplot-962f63413168862fab50da1fe3b6430028277c16.tar.gz
Merge branch 'fix-262' into 'main'
(subplotlib): Ensure that all ContextElement objects implement Debug Closes #262 See merge request subplot/subplot!266
-rw-r--r--subplotlib/helpers/subplotlib_context.rs2
-rw-r--r--subplotlib/src/file.rs2
-rw-r--r--subplotlib/src/prelude.rs6
-rw-r--r--subplotlib/src/scenario.rs75
-rw-r--r--subplotlib/src/steplibrary/datadir.rs14
-rw-r--r--subplotlib/src/steplibrary/files.rs2
-rw-r--r--subplotlib/src/steplibrary/runcmd.rs13
-rw-r--r--subplotlib/subplot-rust-support.rs2
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>,
}