diff options
author | Lars Wirzenius <liw@liw.fi> | 2020-11-13 11:34:02 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2020-11-13 11:34:02 +0200 |
commit | 2f129dee8841f0007977ba80b1518e94b728d94a (patch) | |
tree | 4373cfeec0eda848a8e8feeeb663b32bb80c3323 /subplot | |
parent | 3fe6befd8d1fbcee75df39f6b5b5cd291c75297c (diff) | |
download | obnam2-2f129dee8841f0007977ba80b1518e94b728d94a.tar.gz |
chore: update runcmd Subplot library, move to sublot/vendored
Diffstat (limited to 'subplot')
-rw-r--r-- | subplot/vendored/runcmd.md | 169 | ||||
-rw-r--r-- | subplot/vendored/runcmd.py (renamed from subplot/runcmd.py) | 9 | ||||
-rw-r--r-- | subplot/vendored/runcmd.yaml | 83 |
3 files changed, 261 insertions, 0 deletions
diff --git a/subplot/vendored/runcmd.md b/subplot/vendored/runcmd.md new file mode 100644 index 0000000..bb42005 --- /dev/null +++ b/subplot/vendored/runcmd.md @@ -0,0 +1,169 @@ +# Introduction + +The [Subplot][] library `runcmd` for Python provides scenario steps +and their implementations for running Unix commands and examining the +results. The library consists of a bindings file `lib/runcmd.yaml` and +implementations in Python in `lib/runcmd.py`. There is no Bash +version. + +[Subplot]: https://subplot.liw.fi/ + +This document explains the acceptance criteria for the library and how +they're verified. It uses the steps and functions from the +`lib/runcmd` library. The scenarios all have the same structure: run a +command, then examine the exit code, standard output (stdout for +short), or standard error output (stderr) of the command. + +The scenarios use the Unix commands `/bin/true` and `/bin/false` to +generate exit codes, and `/bin/echo` to produce stdout. To generate +stderr, they use the little helper script below. + +~~~{#err.sh .file .sh .numberLines} +#!/bin/sh +echo "$@" 1>&2 +~~~ + +# Check exit code + +These scenarios verify the exit code. To make it easier to write +scenarios in language that flows more naturally, there are a couple of +variations. + +## Successful execution + +~~~scenario +when I run /bin/true +then exit code is 0 +and command is successful +~~~ + +## Failed execution + +~~~scenario +when I try to run /bin/false +then exit code is not 0 +and command fails +~~~ + +# Check output has what we want + +These scenarios verify that stdout or stderr do have something we want +to have. + +## Check stdout is exactly as wanted + +Note that the string is surrounded by double quotes to make it clear +to the reader what's inside. Also, C-style string escapes are +understood. + +~~~scenario +when I run /bin/echo hello, world +then stdout is exactly "hello, world\n" +~~~ + +## Check stderr is exactly as wanted + +~~~scenario +given helper script err.sh for runcmd +when I run sh err.sh hello, world +then stderr is exactly "hello, world\n" +~~~ + +## Check stdout using sub-string search + +Exact string comparisons are not always enough, so we can verify a +sub-string is in output. + +~~~scenario +when I run /bin/echo hello, world +then stdout contains "world\n" +and exit code is 0 +~~~ + +## Check stderr using sub-string search + +~~~scenario +given helper script err.sh for runcmd +when I run sh err.sh hello, world +then stderr contains "world\n" +~~~ + +## Check stdout using regular expressions + +Fixed strings are not always enough, so we can verify output matches a +regular expression. Note that the regular expression is not delimited +and does not get any C-style string escaped decoded. + +~~~scenario +when I run /bin/echo hello, world +then stdout matches regex world$ +~~~ + +## Check stderr using regular expressions + +~~~scenario +given helper script err.sh for runcmd +when I run sh err.sh hello, world +then stderr matches regex world$ +~~~ + +# Check output doesn't have what we want to avoid + +These scenarios verify that the stdout or stderr do not +have something we want to avoid. + +## Check stdout is not exactly something + +~~~scenario +when I run /bin/echo hi +then stdout isn't exactly "hello, world\n" +~~~ + +## Check stderr is not exactly something + +~~~scenario +given helper script err.sh for runcmd +when I run sh err.sh hi +then stderr isn't exactly "hello, world\n" +~~~ + +## Check stdout doesn't contain sub-string + +~~~scenario +when I run /bin/echo hi +then stdout doesn't contain "world" +~~~ + +## Check stderr doesn't contain sub-string + +~~~scenario +given helper script err.sh for runcmd +when I run sh err.sh hi +then stderr doesn't contain "world" +~~~ + +## Check stdout doesn't match regular expression + +~~~scenario +when I run /bin/echo hi +then stdout doesn't match regex world$ + +~~~ + +## Check stderr doesn't match regular expressions + +~~~scenario +given helper script err.sh for runcmd +when I run sh err.sh hi +then stderr doesn't match regex world$ +~~~ + + +--- +title: Acceptance criteria for the lib/runcmd Subplot library +author: The Subplot project +bindings: +- runcmd.yaml +functions: +- runcmd.py +... diff --git a/subplot/runcmd.py b/subplot/vendored/runcmd.py index 532b60b..a2564c6 100644 --- a/subplot/runcmd.py +++ b/subplot/vendored/runcmd.py @@ -49,7 +49,16 @@ def runcmd_get_argv(ctx): # ctx context. def runcmd_run(ctx, argv, **kwargs): ns = ctx.declare("_runcmd") + + # The Subplot Python template empties os.environ at startup, modulo a small + # number of variables with carefully chosen values. Here, we don't need to + # care about what those variables are, but we do need to not overwrite + # them, so we just add anything in the env keyword argument, if any, to + # os.environ. env = dict(os.environ) + for key, arg in kwargs.pop("env", {}).items(): + env[key] = arg + pp = ns.get("path-prefix") if pp: env["PATH"] = pp + ":" + env["PATH"] diff --git a/subplot/vendored/runcmd.yaml b/subplot/vendored/runcmd.yaml new file mode 100644 index 0000000..48dde90 --- /dev/null +++ b/subplot/vendored/runcmd.yaml @@ -0,0 +1,83 @@ +# Steps to run commands. + +- given: helper script {filename} for runcmd + function: runcmd_helper_script + +- given: srcdir is in the PATH + function: runcmd_helper_srcdir_path + +- when: I run (?P<argv0>\S+)(?P<args>.*) + regex: true + function: runcmd_step + +- when: I try to run (?P<argv0>\S+)(?P<args>.*) + regex: true + function: runcmd_try_to_run + +# Steps to examine exit code of latest command. + +- then: exit code is {exit} + function: runcmd_exit_code_is + +- then: exit code is not {exit} + function: runcmd_exit_code_is_not + +- then: command is successful + function: runcmd_exit_code_is_zero + +- then: command fails + function: runcmd_exit_code_is_nonzero + +# Steps to examine stdout/stderr for exact content. + +- then: stdout is exactly "(?P<text>.*)" + regex: true + function: runcmd_stdout_is + +- then: "stdout isn't exactly \"(?P<text>.*)\"" + regex: true + function: runcmd_stdout_isnt + +- then: stderr is exactly "(?P<text>.*)" + regex: true + function: runcmd_stderr_is + +- then: "stderr isn't exactly \"(?P<text>.*)\"" + regex: true + function: runcmd_stderr_isnt + +# Steps to examine stdout/stderr for sub-strings. + +- then: stdout contains "(?P<text>.*)" + regex: true + function: runcmd_stdout_contains + +- then: "stdout doesn't contain \"(?P<text>.*)\"" + regex: true + function: runcmd_stdout_doesnt_contain + +- then: stderr contains "(?P<text>.*)" + regex: true + function: runcmd_stderr_contains + +- then: "stderr doesn't contain \"(?P<text>.*)\"" + regex: true + function: runcmd_stderr_doesnt_contain + +# Steps to match stdout/stderr against regular expressions. + +- then: stdout matches regex (?P<regex>.*) + regex: true + function: runcmd_stdout_matches_regex + +- then: stdout doesn't match regex (?P<regex>.*) + regex: true + function: runcmd_stdout_doesnt_match_regex + +- then: stderr matches regex (?P<regex>.*) + regex: true + function: runcmd_stderr_matches_regex + +- then: stderr doesn't match regex (?P<regex>.*) + regex: true + function: runcmd_stderr_doesnt_match_regex |