diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2022-03-12 12:02:07 +0000 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2022-03-12 12:02:19 +0000 |
commit | 846090a6057de648708861c39f860f3d0d847837 (patch) | |
tree | 8235783cb2c24d28632e19f9668bec0d8b65f533 /examples | |
parent | 9db59450c07654e6094557c08c9db3b6919b794d (diff) | |
download | subplot-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.toml | 3 | ||||
-rw-r--r-- | examples/seq/seq-extras.rs | 64 | ||||
-rw-r--r-- | examples/seq/seq-extras.yaml | 17 | ||||
-rw-r--r-- | examples/seq/seq.md | 30 |
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 +``` |