diff options
-rw-r--r-- | examples/echo/echo.yaml | 24 | ||||
-rw-r--r-- | examples/muck/muck.yaml | 52 | ||||
-rw-r--r-- | examples/website/website.yaml | 17 | ||||
-rw-r--r-- | share/python/lib/daemon.yaml | 77 | ||||
-rw-r--r-- | share/python/lib/files.yaml | 100 | ||||
-rw-r--r-- | share/python/lib/runcmd.yaml | 96 | ||||
-rw-r--r-- | share/python/lib/runcmd_test.yaml | 8 | ||||
-rw-r--r-- | share/rust/lib/datadir.yaml | 8 | ||||
-rw-r--r-- | share/rust/lib/files.yaml | 100 | ||||
-rw-r--r-- | share/rust/lib/runcmd.yaml | 88 | ||||
-rw-r--r-- | src/bindings.rs | 62 | ||||
-rw-r--r-- | subplot.md | 110 | ||||
-rw-r--r-- | subplot.yaml | 63 | ||||
-rw-r--r-- | subplotlib/subplotlib.yaml | 26 |
14 files changed, 619 insertions, 212 deletions
diff --git a/examples/echo/echo.yaml b/examples/echo/echo.yaml index 7be6e96..bcbdf87 100644 --- a/examples/echo/echo.yaml +++ b/examples/echo/echo.yaml @@ -1,20 +1,32 @@ - when: user runs echo without arguments - function: run_echo_without_args + impl: + bash: + function: run_echo_without_args - when: user runs echo with arguments (?P<args>.+) - function: run_echo_with_args + impl: + bash: + function: run_echo_with_args regex: true - then: exit code is (?P<exit_code>\d+) - function: exit_code_is + impl: + bash: + function: exit_code_is regex: true - then: standard output contains a newline - function: stdout_is_a_newline + impl: + bash: + function: stdout_is_a_newline - then: standard output contains "(?P<text>.*)" - function: stdout_is_text + impl: + bash: + function: stdout_is_text regex: true - then: standard error is empty - function: stderr_is_empty + impl: + bash: + function: stderr_is_empty diff --git a/examples/muck/muck.yaml b/examples/muck/muck.yaml index 21fe303..10f67ee 100644 --- a/examples/muck/muck.yaml +++ b/examples/muck/muck.yaml @@ -1,47 +1,73 @@ - given: "a fresh Muck server" - function: fixme + impl: + python: + function: fixme - given: "I am {name}" - function: fixme + impl: + python: + function: fixme - given: "I am {name}, with super capability" - function: fixme + impl: + python: + function: fixme - when: "I do POST /res with (?P<json>\\{.*\\})" - function: fixme + impl: + python: + function: fixme regex: true - when: "I do PUT /res with Muck-Id: \\{(?P<id>\\S+)\\}, Muck-Revision: \\{(?P<rev>\\S+)\\}, and body (?P<json>\\{.*\\})" - function: fixme + impl: + python: + function: fixme regex: true - when: "I do GET /res with Muck-Id: \\{(?P<id>\\S+)\\}" - function: fixme + impl: + python: + function: fixme regex: true - when: "I do DELETE /res with Muck-Id: \\{(?P<id>\\S+)\\}" - function: fixme + impl: + python: + function: fixme regex: true - when: "I restart Muck" - function: fixme + impl: + python: + function: fixme regex: true - then: "response code is (?P<code>\\d+)" - function: fixme + impl: + python: + function: fixme regex: true - then: "header {header} is {name}" - function: fixme + impl: + python: + function: fixme - then: "header (?P<header>\\S+) matches \\{(?P<name>\\S+)\\}" - function: fixme + impl: + python: + function: fixme regex: true - then: "body matches (?P<json>\\{.*\\})" - function: fixme + impl: + python: + function: fixme regex: true - then: "revisions \\{(?P<rev1>\\S+)\\} and \\{(?P<rev2>\\S+)\\} are different" - function: fixme + impl: + python: + function: fixme regex: true diff --git a/examples/website/website.yaml b/examples/website/website.yaml index 401b16e..a3afc1b 100644 --- a/examples/website/website.yaml +++ b/examples/website/website.yaml @@ -1,12 +1,19 @@ - given: website {url} - function: remember_url + impl: + python: + function: remember_url - when: I look at the front page - function: fetch_url + impl: + python: + function: fetch_url - then: it mentions "{text:text}" - function: page_contains + impl: + python: + function: page_contains - then: it doesn't contain "{text:text}" - function: page_doesnt_contain - + impl: + python: + function: page_doesnt_contain diff --git a/share/python/lib/daemon.yaml b/share/python/lib/daemon.yaml index f4a2f86..5cbc7d0 100644 --- a/share/python/lib/daemon.yaml +++ b/share/python/lib/daemon.yaml @@ -1,59 +1,94 @@ - given: there is no "{args:text}" process - function: daemon_no_such_process + impl: + python: + function: daemon_no_such_process - given: a daemon helper shell script {filename} - function: _daemon_shell_script + impl: + python: + function: _daemon_shell_script - when: I start "{path}{args:text}" as a background process as {name}, on port {port} - function: daemon_start_on_port + impl: + python: + function: daemon_start_on_port - when: I start "(?P<path>[^ "]+)(?P<args>[^"]*)" as a background process as (?P<name>[^,]+), on port (?P<port>\d+), with environment (?P<env>.*) regex: true - function: daemon_start_on_port + impl: + python: + function: daemon_start_on_port - when: I try to start "{path}{args:text}" as {name}, on port {port} - function: _daemon_start_soonish - cleanup: _daemon_stop_soonish + impl: + python: + function: _daemon_start_soonish + cleanup: _daemon_stop_soonish - when: I try to start "(?P<path>[^ "]+)(?P<args>[^"]*)" as (?P<name>[^,]+), on port (?P<port>\d+), with environment (?P<env>.*) regex: true - function: _daemon_start_soonish - cleanup: _daemon_stop_soonish + impl: + python: + function: _daemon_start_soonish + cleanup: _daemon_stop_soonish - when: I start "{path}{args:text}" as a background process as {name} - function: _daemon_start + impl: + python: + function: _daemon_start - when: I start "(?P<path>[^ "]+)(?P<args>[^"]*)" as a background process as (?P<name>[^,]+), with environment (?P<env>.*) regex: true - function: _daemon_start + impl: + python: + function: _daemon_start - when: I stop background process {name} - function: daemon_stop + impl: + python: + function: daemon_stop - when: daemon {name} has produced output - function: daemon_has_produced_output + impl: + python: + function: daemon_has_produced_output - then: a process "{args:text}" is running - function: daemon_process_exists + impl: + python: + function: daemon_process_exists - then: there is no "{args:text}" process - function: daemon_no_such_process + impl: + python: + function: daemon_no_such_process - then: starting daemon fails with "{message:text}" - function: daemon_start_fails_with + impl: + python: + function: daemon_start_fails_with - then: starting the daemon succeeds - function: daemon_start_succeeds + impl: + python: + function: daemon_start_succeeds - then: daemon {name} stdout is "{text:text}" - function: daemon_stdout_is + impl: + python: + function: daemon_stdout_is - then: daemon {name} stdout contains "{text:text}" - function: daemon_stdout_contains + impl: + python: + function: daemon_stdout_contains - then: daemon {name} stdout doesn't contain "{text:text}" - function: daemon_stdout_doesnt_contain + impl: + python: + function: daemon_stdout_doesnt_contain - then: daemon {name} stderr is "{text:text}" - function: daemon_stderr_is - + impl: + python: + function: daemon_stderr_is diff --git a/share/python/lib/files.yaml b/share/python/lib/files.yaml index f18b8cd..64a2d14 100644 --- a/share/python/lib/files.yaml +++ b/share/python/lib/files.yaml @@ -1,83 +1,133 @@ - given: file {filename} - function: files_create_from_embedded + impl: + python: + function: files_create_from_embedded types: filename: file - given: file {filename_on_disk} from {embedded_filename} - function: files_create_from_embedded_with_other_name + impl: + python: + function: files_create_from_embedded_with_other_name types: embedded_filename: file - given: file {filename} has modification time {year}-{month}-{day} {hour}:{minute}:{second} - function: files_touch_with_timestamp + impl: + python: + function: files_touch_with_timestamp - when: I write "(?P<text>.*)" to file (?P<filename>\S+) regex: true - function: files_create_from_text + impl: + python: + function: files_create_from_text - when: I remember metadata for file {filename} - function: files_remember_metadata + impl: + python: + function: files_remember_metadata - when: I touch file {filename} - function: files_touch + impl: + python: + function: files_touch - then: file {filename} exists - function: files_file_exists + impl: + python: + function: files_file_exists - then: file {filename} does not exist - function: files_file_does_not_exist + impl: + python: + function: files_file_does_not_exist - then: only files (?P<filenames>.+) exist - function: files_only_these_exist + impl: + python: + function: files_only_these_exist regex: true - then: file (?P<filename>\S+) contains "(?P<data>.*)" regex: true - function: files_file_contains + impl: + python: + function: files_file_contains - then: file (?P<filename>\S+) matches regex /(?P<regex>.*)/ regex: true - function: files_file_matches_regex + impl: + python: + function: files_file_matches_regex - then: file (?P<filename>\S+) matches regex "(?P<regex>.*)" regex: true - function: files_file_matches_regex + impl: + python: + function: files_file_matches_regex - then: files {filename1} and {filename2} match - function: files_match + impl: + python: + function: files_match - then: file {filename} has same metadata as before - function: files_has_remembered_metadata + impl: + python: + function: files_has_remembered_metadata - then: file {filename} has different metadata from before - function: files_has_different_metadata + impl: + python: + function: files_has_different_metadata - then: file {filename} has changed from before - function: files_has_different_metadata + impl: + python: + function: files_has_different_metadata - then: file {filename} has a very recent modification time - function: files_mtime_is_recent + impl: + python: + function: files_mtime_is_recent - then: file {filename} has a very old modification time - function: files_mtime_is_ancient + impl: + python: + function: files_mtime_is_ancient - given: a directory {path} - function: files_make_directory + impl: + python: + function: files_make_directory - when: I create directory {path} - function: files_make_directory + impl: + python: + function: files_make_directory - when: I remove directory {path} - function: files_remove_directory + impl: + python: + function: files_remove_directory - then: directory {path} exists - function: files_directory_exists + impl: + python: + function: files_directory_exists - then: directory {path} does not exist - function: files_directory_does_not_exist + impl: + python: + function: files_directory_does_not_exist - then: directory {path} is empty - function: files_directory_is_empty + impl: + python: + function: files_directory_is_empty - then: directory {path} is not empty - function: files_directory_is_not_empty + impl: + python: + function: files_directory_is_not_empty diff --git a/share/python/lib/runcmd.yaml b/share/python/lib/runcmd.yaml index a5119d8..a01cfac 100644 --- a/share/python/lib/runcmd.yaml +++ b/share/python/lib/runcmd.yaml @@ -1,91 +1,135 @@ # Steps to run commands. - given: helper script {filename} for runcmd - function: runcmd_helper_script + impl: + python: + function: runcmd_helper_script - given: srcdir is in the PATH - function: runcmd_helper_srcdir_path + impl: + python: + function: runcmd_helper_srcdir_path - when: I run (?P<argv0>\S+)(?P<args>.*) regex: true - function: runcmd_step + impl: + python: + function: runcmd_step - when: I run, in (?P<dirname>\S+), (?P<argv0>\S+)(?P<args>.*) regex: true - function: runcmd_step_in + impl: + python: + function: runcmd_step_in - when: I try to run (?P<argv0>\S+)(?P<args>.*) regex: true - function: runcmd_try_to_run + impl: + python: + function: runcmd_try_to_run - when: I try to run, in (?P<dirname>\S+), (?P<argv0>\S+)(?P<args>.*) regex: true - function: runcmd_try_to_run_in + impl: + python: + function: runcmd_try_to_run_in # Steps to examine exit code of latest command. - then: exit code is {exit} - function: runcmd_exit_code_is + impl: + python: + function: runcmd_exit_code_is - then: exit code is not {exit} - function: runcmd_exit_code_is_not + impl: + python: + function: runcmd_exit_code_is_not - then: command is successful - function: runcmd_exit_code_is_zero + impl: + python: + function: runcmd_exit_code_is_zero - then: command fails - function: runcmd_exit_code_is_nonzero + impl: + python: + 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 + impl: + python: + function: runcmd_stdout_is -- then: "stdout isn't exactly \"(?P<text>.*)\"" +- then: 'stdout isn''t exactly "(?P<text>.*)"' regex: true - function: runcmd_stdout_isnt + impl: + python: + function: runcmd_stdout_isnt - then: stderr is exactly "(?P<text>.*)" regex: true - function: runcmd_stderr_is + impl: + python: + function: runcmd_stderr_is -- then: "stderr isn't exactly \"(?P<text>.*)\"" +- then: 'stderr isn''t exactly "(?P<text>.*)"' regex: true - function: runcmd_stderr_isnt + impl: + python: + function: runcmd_stderr_isnt # Steps to examine stdout/stderr for sub-strings. - then: stdout contains "(?P<text>.*)" regex: true - function: runcmd_stdout_contains + impl: + python: + function: runcmd_stdout_contains -- then: "stdout doesn't contain \"(?P<text>.*)\"" +- then: 'stdout doesn''t contain "(?P<text>.*)"' regex: true - function: runcmd_stdout_doesnt_contain + impl: + python: + function: runcmd_stdout_doesnt_contain - then: stderr contains "(?P<text>.*)" regex: true - function: runcmd_stderr_contains + impl: + python: + function: runcmd_stderr_contains -- then: "stderr doesn't contain \"(?P<text>.*)\"" +- then: 'stderr doesn''t contain "(?P<text>.*)"' regex: true - function: runcmd_stderr_doesnt_contain + impl: + python: + 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 + impl: + python: + function: runcmd_stdout_matches_regex - then: stdout doesn't match regex (?P<regex>.*) regex: true - function: runcmd_stdout_doesnt_match_regex + impl: + python: + function: runcmd_stdout_doesnt_match_regex - then: stderr matches regex (?P<regex>.*) regex: true - function: runcmd_stderr_matches_regex + impl: + python: + function: runcmd_stderr_matches_regex - then: stderr doesn't match regex (?P<regex>.*) regex: true - function: runcmd_stderr_doesnt_match_regex + impl: + python: + function: runcmd_stderr_doesnt_match_regex diff --git a/share/python/lib/runcmd_test.yaml b/share/python/lib/runcmd_test.yaml index 8ade220..2ad981e 100644 --- a/share/python/lib/runcmd_test.yaml +++ b/share/python/lib/runcmd_test.yaml @@ -1,5 +1,9 @@ - given: "executable script {filename} from {embedded}" - function: create_script_from_embedded + impl: + python: + function: create_script_from_embedded - when: "I prepend {dirname} to PATH" - function: runcmd_prepend_to_path + impl: + python: + function: runcmd_prepend_to_path diff --git a/share/rust/lib/datadir.yaml b/share/rust/lib/datadir.yaml index acd4ad4..f4c313b 100644 --- a/share/rust/lib/datadir.yaml +++ b/share/rust/lib/datadir.yaml @@ -4,10 +4,14 @@ # of the capabilities are worth exporting as steps - given: datadir has at least {bytes}B of space - function: subplotlib::steplibrary::datadir::datadir_has_enough_space + impl: + rust: + function: subplotlib::steplibrary::datadir::datadir_has_enough_space types: bytes: uint - given: datadir has at least {megabytes}M of space - function: subplotlib::steplibrary::datadir::datadir_has_enough_space_megabytes + impl: + rust: + function: subplotlib::steplibrary::datadir::datadir_has_enough_space_megabytes types: megabytes: uint diff --git a/share/rust/lib/files.yaml b/share/rust/lib/files.yaml index 5fa4f45..cabda12 100644 --- a/share/rust/lib/files.yaml +++ b/share/rust/lib/files.yaml @@ -2,88 +2,138 @@ # These bind the files step library for subplotlib - given: file {embedded_file} - function: subplotlib::steplibrary::files::create_from_embedded + impl: + rust: + function: subplotlib::steplibrary::files::create_from_embedded types: embedded_file: file - given: file {filename_on_disk} from {embedded_file} - function: subplotlib::steplibrary::files::create_from_embedded_with_other_name + impl: + rust: + function: subplotlib::steplibrary::files::create_from_embedded_with_other_name types: embedded_file: file - given: file (?P<filename>\S+) has modification time (?P<mtime>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) regex: true - function: subplotlib::steplibrary::files::touch_with_timestamp + impl: + rust: + function: subplotlib::steplibrary::files::touch_with_timestamp types: mtime: text - when: I write "(?P<text>.*)" to file (?P<filename>\S+) regex: true - function: subplotlib::steplibrary::files::create_from_text + impl: + rust: + function: subplotlib::steplibrary::files::create_from_text - when: I remember metadata for file {filename} - function: subplotlib::steplibrary::files::remember_metadata + impl: + rust: + function: subplotlib::steplibrary::files::remember_metadata - when: I touch file {filename} - function: subplotlib::steplibrary::files::touch + impl: + rust: + function: subplotlib::steplibrary::files::touch - then: file {filename} exists - function: subplotlib::steplibrary::files::file_exists + impl: + rust: + function: subplotlib::steplibrary::files::file_exists - then: file {filename} does not exist - function: subplotlib::steplibrary::files::file_does_not_exist + impl: + rust: + function: subplotlib::steplibrary::files::file_does_not_exist - then: only files (?P<filenames>.+) exist - function: subplotlib::steplibrary::files::only_these_exist + impl: + rust: + function: subplotlib::steplibrary::files::only_these_exist regex: true - then: file (?P<filename>\S+) contains "(?P<data>.*)" regex: true - function: subplotlib::steplibrary::files::file_contains + impl: + rust: + function: subplotlib::steplibrary::files::file_contains - then: file (?P<filename>\S+) matches regex /(?P<regex>.*)/ regex: true - function: subplotlib::steplibrary::files::file_matches_regex + impl: + rust: + function: subplotlib::steplibrary::files::file_matches_regex - then: file (?P<filename>\S+) matches regex "(?P<regex>.*)" regex: true - function: subplotlib::steplibrary::files::file_matches_regex + impl: + rust: + function: subplotlib::steplibrary::files::file_matches_regex - then: files {filename1} and {filename2} match - function: subplotlib::steplibrary::files::file_match + impl: + rust: + function: subplotlib::steplibrary::files::file_match - then: file {filename} has same metadata as before - function: subplotlib::steplibrary::files::has_remembered_metadata + impl: + rust: + function: subplotlib::steplibrary::files::has_remembered_metadata - then: file {filename} has different metadata from before - function: subplotlib::steplibrary::files::has_different_metadata + impl: + rust: + function: subplotlib::steplibrary::files::has_different_metadata - then: file {filename} has changed from before - function: subplotlib::steplibrary::files::has_different_metadata + impl: + rust: + function: subplotlib::steplibrary::files::has_different_metadata - then: file {filename} has a very recent modification time - function: subplotlib::steplibrary::files::mtime_is_recent + impl: + rust: + function: subplotlib::steplibrary::files::mtime_is_recent - then: file {filename} has a very old modification time - function: subplotlib::steplibrary::files::mtime_is_ancient + impl: + rust: + function: subplotlib::steplibrary::files::mtime_is_ancient - given: a directory {path} - function: subplotlib::steplibrary::files::make_directory + impl: + rust: + function: subplotlib::steplibrary::files::make_directory - when: I create directory {path} - function: subplotlib::steplibrary::files::make_directory + impl: + rust: + function: subplotlib::steplibrary::files::make_directory - when: I remove directory {path} - function: subplotlib::steplibrary::files::remove_directory + impl: + rust: + function: subplotlib::steplibrary::files::remove_directory - then: directory {path} exists - function: subplotlib::steplibrary::files::path_exists + impl: + rust: + function: subplotlib::steplibrary::files::path_exists - then: directory {path} does not exist - function: subplotlib::steplibrary::files::path_does_not_exist + impl: + rust: + function: subplotlib::steplibrary::files::path_does_not_exist - then: directory {path} is empty - function: subplotlib::steplibrary::files::path_is_empty + impl: + rust: + function: subplotlib::steplibrary::files::path_is_empty - then: directory {path} is not empty - function: subplotlib::steplibrary::files::path_is_not_empty + impl: + rust: + function: subplotlib::steplibrary::files::path_is_not_empty diff --git a/share/rust/lib/runcmd.yaml b/share/rust/lib/runcmd.yaml index fc2db6b..1043876 100644 --- a/share/rust/lib/runcmd.yaml +++ b/share/rust/lib/runcmd.yaml @@ -1,97 +1,141 @@ # Bindings for the runcmd steplibrary - given: helper script {script} for runcmd - function: subplotlib::steplibrary::runcmd::helper_script + impl: + rust: + function: subplotlib::steplibrary::runcmd::helper_script types: script: file - given: srcdir is in the PATH - function: subplotlib::steplibrary::runcmd::helper_srcdir_path + impl: + rust: + function: subplotlib::steplibrary::runcmd::helper_srcdir_path - when: I run (?P<argv0>\S+)(?P<args>.*) regex: true - function: subplotlib::steplibrary::runcmd::run + impl: + rust: + function: subplotlib::steplibrary::runcmd::run - when: I run, in (?P<dirname>\S+), (?P<argv0>\S+)(?P<args>.*) regex: true - function: subplotlib::steplibrary::runcmd::run_in + impl: + rust: + function: subplotlib::steplibrary::runcmd::run_in - when: I try to run (?P<argv0>\S+)(?P<args>.*) regex: true - function: subplotlib::steplibrary::runcmd::try_to_run + impl: + rust: + function: subplotlib::steplibrary::runcmd::try_to_run - when: I try to run, in (?P<dirname>\S+), (?P<argv0>\S+)(?P<args>.*) regex: true - function: subplotlib::steplibrary::runcmd::try_to_run_in + impl: + rust: + function: subplotlib::steplibrary::runcmd::try_to_run_in # Steps to examine exit code of latest command. - then: exit code is {exit} - function: subplotlib::steplibrary::runcmd::exit_code_is + impl: + rust: + function: subplotlib::steplibrary::runcmd::exit_code_is types: exit: int - then: exit code is not {exit} - function: subplotlib::steplibrary::runcmd::exit_code_is_not + impl: + rust: + function: subplotlib::steplibrary::runcmd::exit_code_is_not types: exit: int - then: command is successful - function: subplotlib::steplibrary::runcmd::exit_code_is_zero + impl: + rust: + function: subplotlib::steplibrary::runcmd::exit_code_is_zero - then: command fails - function: subplotlib::steplibrary::runcmd::exit_code_is_nonzero + impl: + rust: + function: subplotlib::steplibrary::runcmd::exit_code_is_nonzero # Steps to examine stdout/stderr for exact content. - then: stdout is exactly "(?P<text>.*)" regex: true - function: subplotlib::steplibrary::runcmd::stdout_is + impl: + rust: + function: subplotlib::steplibrary::runcmd::stdout_is - then: 'stdout isn''t exactly "(?P<text>.*)"' regex: true - function: subplotlib::steplibrary::runcmd::stdout_isnt + impl: + rust: + function: subplotlib::steplibrary::runcmd::stdout_isnt - then: stderr is exactly "(?P<text>.*)" regex: true - function: subplotlib::steplibrary::runcmd::stderr_is + impl: + rust: + function: subplotlib::steplibrary::runcmd::stderr_is - then: 'stderr isn''t exactly "(?P<text>.*)"' regex: true - function: subplotlib::steplibrary::runcmd::stderr_isnt + impl: + rust: + function: subplotlib::steplibrary::runcmd::stderr_isnt # Steps to examine stdout/stderr for sub-strings. - then: stdout contains "(?P<text>.*)" regex: true - function: subplotlib::steplibrary::runcmd::stdout_contains + impl: + rust: + function: subplotlib::steplibrary::runcmd::stdout_contains - then: 'stdout doesn''t contain "(?P<text>.*)"' regex: true - function: subplotlib::steplibrary::runcmd::stdout_doesnt_contain + impl: + rust: + function: subplotlib::steplibrary::runcmd::stdout_doesnt_contain - then: stderr contains "(?P<text>.*)" regex: true - function: subplotlib::steplibrary::runcmd::stderr_contains + impl: + rust: + function: subplotlib::steplibrary::runcmd::stderr_contains - then: 'stderr doesn''t contain "(?P<text>.*)"' regex: true - function: subplotlib::steplibrary::runcmd::stderr_doesnt_contain + impl: + rust: + function: subplotlib::steplibrary::runcmd::stderr_doesnt_contain # Steps to match stdout/stderr against regular expressions. - then: stdout matches regex (?P<regex>.*) regex: true - function: subplotlib::steplibrary::runcmd::stdout_matches_regex + impl: + rust: + function: subplotlib::steplibrary::runcmd::stdout_matches_regex - then: stdout doesn't match regex (?P<regex>.*) regex: true - function: subplotlib::steplibrary::runcmd::stdout_doesnt_match_regex + impl: + rust: + function: subplotlib::steplibrary::runcmd::stdout_doesnt_match_regex - then: stderr matches regex (?P<regex>.*) regex: true - function: subplotlib::steplibrary::runcmd::stderr_matches_regex + impl: + rust: + function: subplotlib::steplibrary::runcmd::stderr_matches_regex - then: stderr doesn't match regex (?P<regex>.*) regex: true - function: subplotlib::steplibrary::runcmd::stderr_doesnt_match_regex + impl: + rust: + function: subplotlib::steplibrary::runcmd::stderr_doesnt_match_regex diff --git a/src/bindings.rs b/src/bindings.rs index 5b8d013..9282155 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -10,6 +10,7 @@ use serde_aux::prelude::*; use std::collections::HashMap; use std::fmt::Debug; +use std::ops::Deref; use std::path::Path; use std::str::FromStr; use std::sync::Arc; @@ -206,8 +207,8 @@ impl Binding { } /// Retrieve a particular implementation by name - pub fn step_impl(&self, template: &str) -> Option<Arc<BindingImpl>> { - self.impls.get(template).cloned() + pub fn step_impl(&self, _template: &str) -> Option<Arc<BindingImpl>> { + self.impls.values().next().cloned() } /// Return the compiled regular expression for the pattern of the @@ -399,12 +400,33 @@ impl Default for Bindings { } #[derive(Debug, Deserialize)] +struct ParsedImpl { + function: String, + cleanup: Option<String>, +} + +#[derive(Debug, Deserialize)] +#[serde(transparent)] +struct ParsedImplWrapper { + #[serde(deserialize_with = "deserialize_struct_case_insensitive")] + pimpl: ParsedImpl, +} + +impl Deref for ParsedImplWrapper { + type Target = ParsedImpl; + + fn deref(&self) -> &Self::Target { + &self.pimpl + } +} + +#[derive(Debug, Deserialize)] struct ParsedBinding { given: Option<String>, when: Option<String>, then: Option<String>, - function: String, - cleanup: Option<String>, + #[serde(default, rename = "impl")] + impls: HashMap<String, ParsedImplWrapper>, regex: Option<bool>, #[serde(default)] case_sensitive: bool, @@ -549,7 +571,9 @@ fn from_hashmap(parsed: &ParsedBinding) -> Result<Binding> { let mut ret = Binding::new(kind, &pattern, parsed.case_sensitive, types)?; event!(Level::TRACE, "Binding parsed OK"); - ret.add_impl("", &parsed.function, parsed.cleanup.as_deref()); + for (template, pimpl) in &parsed.impls { + ret.add_impl(template, &pimpl.function, pimpl.cleanup.as_deref()); + } Ok(ret) } @@ -589,16 +613,26 @@ mod test_bindings { fn adds_from_yaml() { let yaml = " - GIVEN: I am Tomjon - function: set_name + impl: + python: + function: set_name - when: I declare myself king - Function: declare_king + impl: + python: + Function: declare_king - tHEn: there is applause - function: check_for_applause + impl: + python: + function: check_for_applause - given: you are alice - function: other_name + impl: + python: + function: other_name case_sensitive: true - then: the total is {total} - function: check_total + impl: + python: + function: check_total types: total: word "; @@ -619,7 +653,9 @@ mod test_bindings { let yaml = " - Given: I am Tomjon wheN: I am indeed Tomjon - FUNCTION: set_name + impl: + python: + FUNCTION: set_name "; match Bindings::new().add_from_yaml(yaml) { Ok(_) => unreachable!(), @@ -632,7 +668,9 @@ mod test_bindings { fn typemap_must_match_pattern() { let yaml = " - then: you are {age:word} years old - function: check_age + impl: + python: + function: check_age types: age: number "; @@ -654,16 +654,24 @@ expresssions ([PCRE][]). ~~~{.yaml .numberLines} - given: "a standard setup" - function: create_standard_setup + impl: + python: + function: create_standard_setup - when: "{thing} happens" - function: make_thing_happen + impl: + python: + function: make_thing_happen types: thing: word - when: "I say (?P<sentence>.+) with a smile" regex: true - function: speak + impl: + python: + function: speak - then: "everything is OK" - function: check_everything_is_ok + impl: + python: + function: check_everything_is_ok ~~~ In the example above, there are four bindings: @@ -925,17 +933,29 @@ then bar was done ~~~{#b.yaml .file .yaml .numberLines} - given: precondition foo - function: precond_foo + impl: + python: + function: precond_foo - when: I do bar - function: do_bar + impl: + python: + function: do_bar - when: I do foobar - function: do_foobar + impl: + python: + function: do_foobar - then: bar was done - function: bar_was_done + impl: + python: + function: bar_was_done - then: foobar was done - function: foobar_was_done + impl: + python: + function: foobar_was_done - given: file {filename} - function: provide_file + impl: + python: + function: provide_file types: filename: file ~~~ @@ -1152,14 +1172,20 @@ test this for every language template we support. ~~~{#cleanup.yaml .file .yaml .numberLines} - given: foo - function: foo - cleanup: foo_cleanup + impl: + python: + function: foo + cleanup: foo_cleanup - given: bar - function: bar - cleanup: bar_cleanup + impl: + python: + function: bar + cleanup: bar_cleanup - given: failure - function: failure - cleanup: failure_cleanup + impl: + python: + function: failure + cleanup: failure_cleanup ~~~ ~~~{#cleanup.py .file .python .numberLines} @@ -1370,7 +1396,9 @@ then TMPDIR is set ~~~{#tmpdir.yaml .file .yaml .numberLines} - then: TMPDIR is set - function: tmpdir_is_set + impl: + python: + function: tmpdir_is_set ~~~ ~~~{#tmpdir.py .file .python .numberLines} @@ -1420,7 +1448,9 @@ given I am Tomjon ~~~{#simplepattern.yaml .file .yaml .numberLines} - given: I am {name} - function: func + impl: + python: + function: func ~~~ ~~~{#capture.py .file .python .numberLines} @@ -1462,7 +1492,9 @@ given I* am Tomjon ~~~{#confusedpattern.yaml .file .yaml .numberLines} - given: I* am {name} - function: func + impl: + python: + function: func ~~~ ### Simple patterns with regex metacharacters: allowed case @@ -1493,7 +1525,9 @@ given I* am Tomjon ~~~{#confusedbutok.yaml .file .yaml .numberLines} - given: I* am {name} - function: func + impl: + python: + function: func regex: false ~~~ @@ -1528,7 +1562,9 @@ given I am Tomjon ~~~{#regex.yaml .file .yaml .numberLines} - given: I am (?P<name>\S+) - function: func + impl: + python: + function: func regex: true ~~~ @@ -1577,10 +1613,14 @@ then expanded "${foo}" is bar ~~~{#values.yaml .file .yaml .numberLines} - when: I remember {name} as {value} - function: remember + impl: + python: + function: remember - then: expanded "{actual}" is {expected} - function: check + impl: + python: + function: check ~~~ ~~~{#values.py .file .python .numberLines} @@ -1643,7 +1683,9 @@ then environment variable FOO is set to "bar" ~~~{#env.yaml .file .yaml .numberLines} - then: environment variable {name} is set to "{value:text}" - function: is_set_to + impl: + python: + function: is_set_to ~~~ ~~~{#env.py .file .python .numberLines} @@ -2541,12 +2583,18 @@ binding. ```{#badbindings.yaml .file .yaml} - given: a binding - function: a_binding + impl: + python: + function: a_binding - given: a (?:broken)? binding - function: a_broken_binding + impl: + python: + function: a_broken_binding regex: true - given: a capitalised Binding - function: os.getcwd + impl: + python: + function: os.getcwd case_sensitive: true ``` @@ -2618,9 +2666,13 @@ given a binding ~~~{#twobindings.yaml .file .yaml} - given: a {xyzzy} - function: a_function + impl: + python: + function: a_function - given: a {plugh} - function: a_function + impl: + python: + function: a_function ~~~ ~~~{#a_function.py .file .python} diff --git a/subplot.yaml b/subplot.yaml index c7c0c4e..229cc7d 100644 --- a/subplot.yaml +++ b/subplot.yaml @@ -1,48 +1,71 @@ - given: an installed subplot - function: install_subplot - cleanup: uninstall_subplot + impl: + python: + function: install_subplot + cleanup: uninstall_subplot - then: scenario "(?P<name>.+)" was run - function: scenario_was_run + impl: + python: + function: scenario_was_run regex: true - then: scenario "(?P<name>.+)" was not run - function: scenario_was_not_run + impl: + python: + function: scenario_was_not_run regex: true - then: step "(?P<keyword>given|when|then) (?P<name>.+)" was run - function: step_was_run + impl: + python: + function: step_was_run regex: true - then: step "(?P<keyword1>given|when|then) (?P<name1>.+)" was run, and then step "(?P<keyword2>given|when|then) (?P<name2>.+)" - function: step_was_run_and_then + impl: + python: + function: step_was_run_and_then regex: true - then: cleanup for "(?P<keyword1>given|when|then) (?P<name1>.+)" was run, and then for "(?P<keyword2>given|when|then) (?P<name2>.+)" - function: cleanup_was_run + impl: + python: + function: cleanup_was_run regex: true - then: cleanup for "(?P<keyword>given|when|then) (?P<name>.+)" was not run - function: cleanup_was_not_run + impl: + python: + function: cleanup_was_not_run regex: true - - then: JSON output matches {filename} - function: json_output_matches_file + impl: + python: + function: json_output_matches_file - then: "{filename} does not end in a newline" - function: file_ends_in_zero_newlines + impl: + python: + function: file_ends_in_zero_newlines - then: "{filename} ends in one newline" - function: file_ends_in_one_newline + impl: + python: + function: file_ends_in_one_newline - then: "{filename} ends in two newlines" - function: file_ends_in_two_newlines + impl: + python: + function: file_ends_in_two_newlines # In order to cope with low granularity filesystems, sometimes we need to wait # for things to happen - when: I wait until (?P<delay>\d+) seconds? has passed - function: sleep_seconds + impl: + python: + function: sleep_seconds regex: true types: delay: uint @@ -50,10 +73,16 @@ # The following are purely descriptive steps and are not used to test anything - given: the necessary starting conditions - function: do_nothing + impl: + python: + function: do_nothing - when: I do the required actions - function: do_nothing + impl: + python: + function: do_nothing - then: the desired outcome is achieved - function: do_nothing + impl: + python: + function: do_nothing diff --git a/subplotlib/subplotlib.yaml b/subplotlib/subplotlib.yaml index 78090c3..f92ff24 100644 --- a/subplotlib/subplotlib.yaml +++ b/subplotlib/subplotlib.yaml @@ -1,20 +1,32 @@ - given: a counter starting at {initial} - function: a_trivial_setup - cleanup: a_trivial_cleanup + impl: + rust: + function: a_trivial_setup + cleanup: a_trivial_cleanup types: initial: int - when: the counter is incremented - function: increment_counter + impl: + rust: + function: increment_counter - then: the counter is {num} - function: check_counter + impl: + rust: + function: check_counter types: num: number - given: I have read the file {file} into {somename} - function: acquire_file_content + impl: + rust: + function: acquire_file_content types: file: file somename: text - when: I look at {somename} - function: remember_target + impl: + rust: + function: remember_target - then: I see "{text:text}" - function: check_contents + impl: + rust: + function: check_contents |