summaryrefslogtreecommitdiff
path: root/subplotlib
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2020-12-05 11:13:43 +0000
committerDaniel Silverstone <dsilvers@digital-scurf.org>2020-12-21 08:39:32 +0000
commit515096221b94857725e445a9669d3b2f239a9453 (patch)
tree2927056b99ad5300911f90844845ffeb44493d95 /subplotlib
parent91b29f9bd7e34434824789d33014c916e7e13243 (diff)
downloadsubplot-515096221b94857725e445a9669d3b2f239a9453.tar.gz
subplotlib: Add a bunch of documentation
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
Diffstat (limited to 'subplotlib')
-rw-r--r--subplotlib/src/args.rs1
-rw-r--r--subplotlib/src/file.rs45
-rw-r--r--subplotlib/src/lib.rs8
-rw-r--r--subplotlib/src/prelude.rs10
-rw-r--r--subplotlib/src/scenario.rs30
-rw-r--r--subplotlib/src/step.rs32
-rw-r--r--subplotlib/src/types.rs13
-rw-r--r--subplotlib/src/utils.rs8
8 files changed, 136 insertions, 11 deletions
diff --git a/subplotlib/src/args.rs b/subplotlib/src/args.rs
deleted file mode 100644
index 8b13789..0000000
--- a/subplotlib/src/args.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/subplotlib/src/file.rs b/subplotlib/src/file.rs
index 1be93df..e44c0ef 100644
--- a/subplotlib/src/file.rs
+++ b/subplotlib/src/file.rs
@@ -1,10 +1,39 @@
//! Subplot data files
-//
+//!
+//! Subplot can embed data files into test suites. This module provides
+//! the representation of the files in a way designed to be cheap to clone
+//! so that they can be passed around "by value".
use std::path::{Path, PathBuf};
use std::sync::Arc;
use base64::decode;
+/// An embedded data file.
+///
+/// Embedded data files have names and content. The subplot template will generate
+/// a `lazy_static` containing all the data files embedded into the suite. Then
+/// generated test functions will extract data files
+///
+/// If you are using them in your test steps you should take them by value:
+///
+/// ```rust
+/// # use subplotlib::prelude::*;
+/// # struct Context {}
+/// #[step]
+/// fn step_using_a_file(context: &mut Context, somefile: SubplotDataFile) {
+/// // context.stash_file(somefile);
+/// }
+/// ```
+///
+/// For the generated test to correctly recognise how to pass a file in, you
+/// **must** mark the argument as a file in your binding:
+///
+/// ```yaml
+/// - when: using {somefile} as a input
+/// function: step_using_a_file
+/// types:
+/// somefile: file
+/// ```
#[derive(Debug)]
pub struct SubplotDataFile {
name: Arc<Path>,
@@ -30,6 +59,18 @@ impl Default for SubplotDataFile {
}
impl SubplotDataFile {
+ /// Construct a new data file object
+ ///
+ /// Typically this will only be called from the generated test suite.
+ /// The passed in name and data must be base64 encoded strings and each will
+ /// be interpreted independently. The name will be treated as a [`PathBuf`]
+ /// and the data will be stored as a slice of bytes.
+ ///
+ /// Neither will be interpreted as utf8.
+ ///
+ /// # Panics
+ ///
+ /// This will panic if the passed in strings are not correctly base64 encoded.
pub fn new(name: &str, data: &str) -> Self {
let name = decode(name).expect("Subplot generated bad base64?");
let name = String::from_utf8_lossy(&name);
@@ -39,10 +80,12 @@ impl SubplotDataFile {
Self { name, data }
}
+ /// Retrieve the filename
pub fn name(&self) -> &Path {
&self.name
}
+ /// Retrieve the data
pub fn data(&self) -> &[u8] {
&self.data
}
diff --git a/subplotlib/src/lib.rs b/subplotlib/src/lib.rs
index 9ebae0f..8c31672 100644
--- a/subplotlib/src/lib.rs
+++ b/subplotlib/src/lib.rs
@@ -1,6 +1,14 @@
//! Subplot test utilities
//!
+//! This crate is meant to be used by test suites generated using the [Subplot][]
+//! code generator using the `rust` template. You should generally not use this
+//! crate directly, instead test suites generated using the `rust` template will
+//! `use subplotlib::prelude::*;` automatically.
//!
+//! If you want to explore things, then we suggest you start from the [`prelude`][mod@prelude]
+//! module since it exposes everything you'd normally find in a test suite.
+//!
+//! [Subplot]: https://subplot.liw.fi/
pub mod file;
pub mod prelude;
diff --git a/subplotlib/src/prelude.rs b/subplotlib/src/prelude.rs
index 1368d1e..d093e0f 100644
--- a/subplotlib/src/prelude.rs
+++ b/subplotlib/src/prelude.rs
@@ -1,27 +1,37 @@
//! The subplotlib prelude
// Re-export fehler's macros so that step functions can use them
+#[doc(inline)]
pub use fehler::throw;
+#[doc(inline)]
pub use fehler::throws;
// Re-export the lazy_static macro
+#[doc(inline)]
pub use lazy_static::lazy_static;
// Re-export subplotlib-derive's macros so that #[step] works
+#[doc(inline)]
pub use subplotlib_derive::step;
// Re-export the step result types
+#[doc(inline)]
pub use crate::types::StepError;
+#[doc(inline)]
pub use crate::types::StepResult;
// And the step itself
+#[doc(inline)]
pub use crate::step::ScenarioStep;
// Data files
+#[doc(inline)]
pub use crate::file::SubplotDataFile;
// Finally a scenario itself
+#[doc(inline)]
pub use crate::scenario::Scenario;
// Utility functions
+#[doc(inline)]
pub use crate::utils::base64_decode;
diff --git a/subplotlib/src/scenario.rs b/subplotlib/src/scenario.rs
index 5511d81..7b2b1ba 100644
--- a/subplotlib/src/scenario.rs
+++ b/subplotlib/src/scenario.rs
@@ -1,10 +1,17 @@
-//! Scenario
-//
+//! Scenarios
+//!
+//! In general you will not need to interact with the [`Scenario`] type directly.
+//! Instead instances of it are constructed in the generated test functions and
+//! will be run automatically.
use crate::step::ScenarioStep;
use crate::types::StepError;
-/// A Scenario is the embodiment of something which can be run as a scenario.
+/// The embodiment of a subplot scenario
+///
+/// Scenario objects are built up by the generated test functions and then run
+/// to completion. In rare cases they may be built up and cached for reuse
+/// for example if a scenario is a subroutine.
pub struct Scenario<C> {
title: String,
steps: Vec<(ScenarioStep<C>, Option<ScenarioStep<C>>)>,
@@ -14,6 +21,7 @@ impl<C> Scenario<C>
where
C: Default,
{
+ /// Create a new scenario with the given title
pub fn new(title: &str) -> Self {
Self {
title: title.to_string(),
@@ -21,10 +29,26 @@ where
}
}
+ /// Retrieve the scenario title
+ pub fn title(&self) -> &str {
+ &self.title
+ }
+
+ /// Add a scenario step, with optional cleanup step function.
pub fn add_step(&mut self, step: ScenarioStep<C>, cleanup: Option<ScenarioStep<C>>) {
self.steps.push((step, cleanup));
}
+ /// Run the scenario to completion.
+ ///
+ /// Running the scenario to completion requires running each step in turn.
+ /// This will return the first encountered error, or unit if the scenario
+ /// runs cleanly.
+ ///
+ /// # Panics
+ ///
+ /// If any of the cleanup functions error, this will immediately panic.
+ ///
pub fn run(self) -> Result<(), StepError> {
let mut highest = None;
let mut context = C::default();
diff --git a/subplotlib/src/step.rs b/subplotlib/src/step.rs
index cdfba74..6b4c334 100644
--- a/subplotlib/src/step.rs
+++ b/subplotlib/src/step.rs
@@ -1,22 +1,35 @@
//! Scenario steps
+//!
+//! In general you will not need to interact with these types, they're simply
+//! here to provide wrappers to make the scenarios easier to work with.
+//!
use crate::types::StepResult;
-/// StepFunctions are one of the StepFunction or MutableStepFunction type
+/// Step functions
+///
+/// Each step function might take a mutable or immutable borrow of the context
+/// which is used in the scenario.
enum StepFunctions<C> {
Immutable(Box<dyn Fn(&C) -> StepResult>),
Mutable(Box<dyn Fn(&mut C) -> StepResult>),
}
-/// A ScenarioStep is one step in a scenario. It is, quite simply, a
-/// named closure.
+/// A ScenarioStep is one step in a scenario.
///
+/// In essence, a scenario step is a named closure. Its name can be used when
+/// reporting an error encountered in running a scenario.
pub struct ScenarioStep<C> {
name: String,
func: StepFunctions<C>,
}
impl<C> ScenarioStep<C> {
+ /// Create a new scenario step taking an immutable context
+ ///
+ /// This is used to construct a scenario step from a function which
+ /// takes an immutable borrow of the context. This will generally be
+ /// called from the generated build method for the step.
pub fn new_immutable<F>(name: &str, func: F) -> Self
where
F: Fn(&C) -> StepResult + 'static,
@@ -27,6 +40,11 @@ impl<C> ScenarioStep<C> {
}
}
+ /// Create a new scenario step taking a mutable context
+ ///
+ /// This is used to construct a scenario step from a functino which
+ /// takes a mutable borrow of the context. This will generally be
+ /// called from the generated build method for the step.
pub fn new_mutable<F>(name: &str, func: F) -> Self
where
F: Fn(&mut C) -> StepResult + 'static,
@@ -37,10 +55,18 @@ impl<C> ScenarioStep<C> {
}
}
+ /// Call the step function
+ ///
+ /// This simply calls the encased step function
pub fn call(&self, context: &mut C) -> StepResult {
match &self.func {
StepFunctions::Immutable(f) => f(context),
StepFunctions::Mutable(f) => f(context),
}
}
+
+ /// Return the name of this step
+ pub fn name(&self) -> &str {
+ &self.name
+ }
}
diff --git a/subplotlib/src/types.rs b/subplotlib/src/types.rs
index 09efe8b..963ce87 100644
--- a/subplotlib/src/types.rs
+++ b/subplotlib/src/types.rs
@@ -1,6 +1,17 @@
//! Fundamental types used throughout subplotlib
/// Generic error type which steps can return.
+///
+/// Step functions constructed using the [`step`][macro@subplotlib_derive::step]
+/// macro will automatically return this as the error type. It is pretty
+/// generic meaning that almost every possible use of the `?` operator should
+/// work.
pub type StepError = ::std::boxed::Box<dyn ::std::error::Error>;
-/// Result type using that, useful for use in #[throws]
+
+/// Result type using [`StepError`].
+///
+/// This is useful for use in situations where you
+/// might use [`#[throws(...)]`][macro@fehler::throws]. Step functions
+/// generated using the [`step`][macro@subplotlib_derive::step] macro will
+/// automatically set this as their return type by means of `#[throws(StepResult)]`.
pub type StepResult = ::std::result::Result<(), StepError>;
diff --git a/subplotlib/src/utils.rs b/subplotlib/src/utils.rs
index f7f1d5f..ee60f06 100644
--- a/subplotlib/src/utils.rs
+++ b/subplotlib/src/utils.rs
@@ -1,8 +1,12 @@
-//! Utility functions
+//! Utility functions used by subplotlib or the generated test functions
/// Decode a base64 string.
///
-/// Note: Will panic if it's not valid base64 leading to a string
+/// If the result is not a valid utf8 string then it is lossily coerced.
+///
+/// # Panics
+///
+/// Will panic if it's not valid base64 leading to a string.
pub fn base64_decode(input: &str) -> String {
let dec = base64::decode(input).expect("bad base64");
String::from_utf8_lossy(&dec).to_string()