summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2022-03-12 12:02:07 +0000
committerDaniel Silverstone <dsilvers@digital-scurf.org>2022-03-12 12:02:19 +0000
commit846090a6057de648708861c39f860f3d0d847837 (patch)
tree8235783cb2c24d28632e19f9668bec0d8b65f533 /examples
parent9db59450c07654e6094557c08c9db3b6919b794d (diff)
downloadsubplot-846090a6057de648708861c39f860f3d0d847837.tar.gz
(examples): Add step functions to seq example
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
Diffstat (limited to 'examples')
-rw-r--r--examples/seq/Cargo.toml3
-rw-r--r--examples/seq/seq-extras.rs64
-rw-r--r--examples/seq/seq-extras.yaml17
-rw-r--r--examples/seq/seq.md30
4 files changed, 111 insertions, 3 deletions
diff --git a/examples/seq/Cargo.toml b/examples/seq/Cargo.toml
index e0f577a..7e2e78c 100644
--- a/examples/seq/Cargo.toml
+++ b/examples/seq/Cargo.toml
@@ -5,8 +5,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-[dependencies]
+[dev-dependencies]
subplotlib = { path = "../../subplotlib" }
+fehler = "1"
[build-dependencies]
subplot-build = { path = "../../subplot-build" }
diff --git a/examples/seq/seq-extras.rs b/examples/seq/seq-extras.rs
new file mode 100644
index 0000000..79863fc
--- /dev/null
+++ b/examples/seq/seq-extras.rs
@@ -0,0 +1,64 @@
+// This is an example step library.
+
+// Our step function uses the subplotlib Runcmd context
+// in order that it can access the stdout of the recently
+// executed command.
+use subplotlib::steplibrary::runcmd::Runcmd;
+
+// All step functions are annotated with the #[step] attribute
+// which is implemented in the subplotlib-derive crate.
+// This marks the function as a step function and automatically
+// creates the step builders and other code needed to be able to
+// use this step in a scenario.
+#[step]
+// The first argument to a step function is always the context with
+// which the step is run. If the step is simple (needs only one
+// context) then this will be a borrow (or mut borrow) of the context
+// type. If the step uses multiple kinds of context then instead there
+// will be some number of #[context(TypeName)] attributes, and the step
+// function will take a ScenarioContext as its context argument.
+// The rest of the arguments to the step function are the captures from the
+// binding for the step.
+fn count_lines_in_stdout(context: &Runcmd, count: usize) {
+ let stdout_count = context.stdout_as_string().lines().count();
+ if stdout_count != count {
+ // Step functions can use the throw!() macro to raise a
+ // step error. This will be reported as the reason the
+ // scenario fails.
+ throw!(format!(
+ "Incorrect number of lines, got {} expected {}",
+ stdout_count, count
+ ));
+ }
+}
+
+// While this step function could just use Runcmd again, we use ScenarioContext
+// in order to demonstrate how to access other contexts from a generic step
+// function in Rust
+
+#[step]
+#[context(Runcmd)]
+fn stderr_contains_two_things(context: &ScenarioContext, what: &str, other: &str) {
+ // To keep lifetimes sane, you access other contexts by using closures which
+ // take the context as an argument.
+ let stderr_has_both = context.with(
+ |runcmd: &Runcmd| {
+ // In here, `runcmd` is the context we need
+ let stderr = runcmd.stderr_as_string();
+ // Since we could fail in here, we're actually returning a Result object
+ Ok(stderr.contains(what) && stderr.contains(other))
+ },
+ // This `false` means that we will not run the closure if the scenario is
+ // currently failing. This is more useful in cleanup functions since it
+ // allows you to decide if you want to ignore the failure mode in order to
+ // clean up more effectively.
+ false,
+ )?;
+
+ if !stderr_has_both {
+ throw!(format!(
+ "Stderr does not contain both of {:?} and {:?}",
+ what, other
+ ))
+ }
+}
diff --git a/examples/seq/seq-extras.yaml b/examples/seq/seq-extras.yaml
new file mode 100644
index 0000000..80fb9d7
--- /dev/null
+++ b/examples/seq/seq-extras.yaml
@@ -0,0 +1,17 @@
+# Extra step functions for use in the `seq` example
+
+# For help with bindings files, see the main documentation for subplot
+
+- then: stdout has (?P<count>[0-9]+) lines?
+ regex: true
+ types:
+ count: uint
+ impl:
+ rust:
+ function: count_lines_in_stdout
+
+
+- then: stderr says {what} is {other}
+ impl:
+ rust:
+ function: stderr_contains_two_things
diff --git a/examples/seq/seq.md b/examples/seq/seq.md
index da51a3f..d00c696 100644
--- a/examples/seq/seq.md
+++ b/examples/seq/seq.md
@@ -2,9 +2,11 @@
title: "**seq**(1) acceptance tests"
author: The Subplot project
bindings:
-- lib/runcmd.yaml
+ - lib/runcmd.yaml
+ - seq-extras.yaml
impls:
- rust: []
+ rust:
+ - seq-extras.rs
...
# Introduction
@@ -42,3 +44,27 @@ when I run seq 1
then stdout is exactly "1\n"
then stderr is exactly ""
```
+
+# More than one number
+
+_Requirement: If `seq` is run with the argument 3, it writes three lines,
+one with the number 1, one with 2, and one with 3._
+
+```scenario
+when I run seq 3
+then stdout has 3 lines
+then stdout is exactly "1\n2\n3\n"
+then stderr is exactly ""
+```
+
+# Not a number
+
+_Requirement: If `seq` is run with a non-numerical argument, it writes nothing
+to stdout, and an error message to stderr._
+
+```scenario
+when I try to run seq fish
+then command fails
+then stdout is exactly ""
+then stderr says fish is invalid
+```