summaryrefslogtreecommitdiff
path: root/share
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-09-13 09:44:39 +0000
committerLars Wirzenius <liw@liw.fi>2021-09-13 09:44:39 +0000
commita06ef1f46c8603b8b5e5a44e6521b10238331891 (patch)
tree995392da4d56597be9ac71bba4669df299506ea7 /share
parent217d920d72d9bf56174e0694329ef9c558160b69 (diff)
parent66bedaf70e7b652f791dd0e2fcbd39db3cbec6f9 (diff)
downloadsubplot-a06ef1f46c8603b8b5e5a44e6521b10238331891.tar.gz
Merge branch 'multi-lang-docs' into 'main'
Implement polyglot bindings See merge request subplot/subplot!210
Diffstat (limited to 'share')
-rw-r--r--share/common/lib/files.yaml188
-rw-r--r--share/common/lib/runcmd.yaml185
-rw-r--r--share/python/lib/daemon.md189
-rw-r--r--share/python/lib/daemon.yaml77
-rw-r--r--share/python/lib/files.md105
-rw-r--r--share/python/lib/files.py35
-rw-r--r--share/python/lib/files.yaml83
-rw-r--r--share/python/lib/runcmd.md214
-rw-r--r--share/python/lib/runcmd.py6
-rw-r--r--share/python/lib/runcmd.yaml91
-rw-r--r--share/python/lib/runcmd_test.py15
-rw-r--r--share/python/lib/runcmd_test.yaml5
-rw-r--r--share/rust/lib/datadir.yaml8
-rw-r--r--share/rust/lib/files.yaml89
-rw-r--r--share/rust/lib/runcmd.yaml97
15 files changed, 447 insertions, 940 deletions
diff --git a/share/common/lib/files.yaml b/share/common/lib/files.yaml
new file mode 100644
index 0000000..40c092a
--- /dev/null
+++ b/share/common/lib/files.yaml
@@ -0,0 +1,188 @@
+# Bindings for the files steps
+
+- given: file {embedded_file}
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::create_from_embedded
+ python:
+ function: files_create_from_embedded
+ types:
+ embedded_file: file
+
+- given: file {filename_on_disk} from {embedded_file}
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::create_from_embedded_with_other_name
+ python:
+ function: 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
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::touch_with_timestamp
+ python:
+ function: files_touch_with_timestamp
+ types:
+ mtime: text
+
+- when: I write "(?P<text>.*)" to file (?P<filename>\S+)
+ regex: true
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::create_from_text
+ python:
+ function: files_create_from_text
+
+- when: I remember metadata for file {filename}
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::remember_metadata
+ python:
+ function: files_remember_metadata
+
+- when: I touch file {filename}
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::touch
+ python:
+ function: files_touch
+
+- then: file {filename} exists
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::file_exists
+ python:
+ function: files_file_exists
+
+- then: file {filename} does not exist
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::file_does_not_exist
+ python:
+ function: files_file_does_not_exist
+
+- then: only files (?P<filenames>.+) exist
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::only_these_exist
+ python:
+ function: files_only_these_exist
+ regex: true
+
+- then: file (?P<filename>\S+) contains "(?P<data>.*)"
+ regex: true
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::file_contains
+ python:
+ function: files_file_contains
+
+- then: file (?P<filename>\S+) matches regex /(?P<regex>.*)/
+ regex: true
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::file_matches_regex
+ python:
+ function: files_file_matches_regex
+
+- then: file (?P<filename>\S+) matches regex "(?P<regex>.*)"
+ regex: true
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::file_matches_regex
+ python:
+ function: files_file_matches_regex
+
+- then: files {filename1} and {filename2} match
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::file_match
+ python:
+ function: files_match
+
+- then: file {filename} has same metadata as before
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::has_remembered_metadata
+ python:
+ function: files_has_remembered_metadata
+
+- then: file {filename} has different metadata from before
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::has_different_metadata
+ python:
+ function: files_has_different_metadata
+
+- then: file {filename} has changed from before
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::has_different_metadata
+ python:
+ function: files_has_different_metadata
+
+- then: file {filename} has a very recent modification time
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::mtime_is_recent
+ python:
+ function: files_mtime_is_recent
+
+- then: file {filename} has a very old modification time
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::mtime_is_ancient
+ python:
+ function: files_mtime_is_ancient
+
+- given: a directory {path}
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::make_directory
+ python:
+ function: files_make_directory
+
+- when: I create directory {path}
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::make_directory
+ python:
+ function: files_make_directory
+
+- when: I remove directory {path}
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::remove_directory
+ python:
+ function: files_remove_directory
+
+- then: directory {path} exists
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::path_exists
+ python:
+ function: files_directory_exists
+
+- then: directory {path} does not exist
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::path_does_not_exist
+ python:
+ function: files_directory_does_not_exist
+
+- then: directory {path} is empty
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::path_is_empty
+ python:
+ function: files_directory_is_empty
+
+- then: directory {path} is not empty
+ impl:
+ rust:
+ function: subplotlib::steplibrary::files::path_is_not_empty
+ python:
+ function: files_directory_is_not_empty
diff --git a/share/common/lib/runcmd.yaml b/share/common/lib/runcmd.yaml
new file mode 100644
index 0000000..bde2f69
--- /dev/null
+++ b/share/common/lib/runcmd.yaml
@@ -0,0 +1,185 @@
+# Bindings for the runcmd steplibrary
+
+- given: helper script {script} for runcmd
+ impl:
+ python:
+ function: runcmd_helper_script
+ rust:
+ function: subplotlib::steplibrary::runcmd::helper_script
+ types:
+ script: file
+
+- given: srcdir is in the PATH
+ impl:
+ python:
+ function: runcmd_helper_srcdir_path
+ rust:
+ function: subplotlib::steplibrary::runcmd::helper_srcdir_path
+
+- when: I run (?P<argv0>\S+)(?P<args>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_step
+ rust:
+ function: subplotlib::steplibrary::runcmd::run
+
+- when: I run, in (?P<dirname>\S+), (?P<argv0>\S+)(?P<args>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_step_in
+ rust:
+ function: subplotlib::steplibrary::runcmd::run_in
+
+- when: I try to run (?P<argv0>\S+)(?P<args>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_try_to_run
+ rust:
+ function: subplotlib::steplibrary::runcmd::try_to_run
+
+- when: I try to run, in (?P<dirname>\S+), (?P<argv0>\S+)(?P<args>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_try_to_run_in
+ rust:
+ function: subplotlib::steplibrary::runcmd::try_to_run_in
+
+# Steps to examine exit code of latest command.
+
+- then: exit code is {exit}
+ impl:
+ python:
+ function: runcmd_exit_code_is
+ rust:
+ function: subplotlib::steplibrary::runcmd::exit_code_is
+ types:
+ exit: int
+
+- then: exit code is not {exit}
+ impl:
+ python:
+ function: runcmd_exit_code_is_not
+ rust:
+ function: subplotlib::steplibrary::runcmd::exit_code_is_not
+ types:
+ exit: int
+
+- then: command is successful
+ impl:
+ python:
+ function: runcmd_exit_code_is_zero
+ rust:
+ function: subplotlib::steplibrary::runcmd::exit_code_is_zero
+
+- then: command fails
+ impl:
+ python:
+ function: runcmd_exit_code_is_nonzero
+ 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
+ impl:
+ python:
+ function: runcmd_stdout_is
+ rust:
+ function: subplotlib::steplibrary::runcmd::stdout_is
+
+- then: 'stdout isn''t exactly "(?P<text>.*)"'
+ regex: true
+ impl:
+ python:
+ function: runcmd_stdout_isnt
+ rust:
+ function: subplotlib::steplibrary::runcmd::stdout_isnt
+
+- then: stderr is exactly "(?P<text>.*)"
+ regex: true
+ impl:
+ python:
+ function: runcmd_stderr_is
+ rust:
+ function: subplotlib::steplibrary::runcmd::stderr_is
+
+- then: 'stderr isn''t exactly "(?P<text>.*)"'
+ regex: true
+ impl:
+ python:
+ function: runcmd_stderr_isnt
+ rust:
+ function: subplotlib::steplibrary::runcmd::stderr_isnt
+
+# Steps to examine stdout/stderr for sub-strings.
+
+- then: stdout contains "(?P<text>.*)"
+ regex: true
+ impl:
+ python:
+ function: runcmd_stdout_contains
+ rust:
+ function: subplotlib::steplibrary::runcmd::stdout_contains
+
+- then: 'stdout doesn''t contain "(?P<text>.*)"'
+ regex: true
+ impl:
+ python:
+ function: runcmd_stdout_doesnt_contain
+ rust:
+ function: subplotlib::steplibrary::runcmd::stdout_doesnt_contain
+
+- then: stderr contains "(?P<text>.*)"
+ regex: true
+ impl:
+ python:
+ function: runcmd_stderr_contains
+ rust:
+ function: subplotlib::steplibrary::runcmd::stderr_contains
+
+- then: 'stderr doesn''t contain "(?P<text>.*)"'
+ regex: true
+ impl:
+ python:
+ function: runcmd_stderr_doesnt_contain
+ rust:
+ function: subplotlib::steplibrary::runcmd::stderr_doesnt_contain
+
+# Steps to match stdout/stderr against regular expressions.
+
+- then: stdout matches regex (?P<regex>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_stdout_matches_regex
+ rust:
+ function: subplotlib::steplibrary::runcmd::stdout_matches_regex
+
+- then: stdout doesn't match regex (?P<regex>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_stdout_doesnt_match_regex
+ rust:
+ function: subplotlib::steplibrary::runcmd::stdout_doesnt_match_regex
+
+- then: stderr matches regex (?P<regex>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_stderr_matches_regex
+ rust:
+ function: subplotlib::steplibrary::runcmd::stderr_matches_regex
+
+- then: stderr doesn't match regex (?P<regex>.*)
+ regex: true
+ impl:
+ python:
+ function: runcmd_stderr_doesnt_match_regex
+ rust:
+ function: subplotlib::steplibrary::runcmd::stderr_doesnt_match_regex
diff --git a/share/python/lib/daemon.md b/share/python/lib/daemon.md
deleted file mode 100644
index c7bb49f..0000000
--- a/share/python/lib/daemon.md
+++ /dev/null
@@ -1,189 +0,0 @@
-# Introduction
-
-The [Subplot][] library `daemon` for Python provides scenario steps
-and their implementations for running a background process and
-terminating at the end of the scenario.
-
-[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/daemon` library. The scenarios all have the same structure: run a
-command, then examine the exit code, verify the process is running.
-
-# Daemon is started and terminated
-
-This scenario starts a background process, verifies it's started, and
-verifies it's terminated after the scenario ends.
-
-~~~scenario
-given there is no "/bin/sleep 12765" process
-when I start "/bin/sleep 12765" as a background process as sleepyhead
-then a process "/bin/sleep 12765" is running
-when I stop background process sleepyhead
-then there is no "/bin/sleep 12765" process
-~~~
-
-
-# Daemon takes a while to open its port
-
-This scenario verifies that if the background process doesn't immediately start
-listening on its port, the daemon library handles that correctly. We do this
-with a helper script that waits 2 seconds before opening the port. The
-lib/daemon code will wait for the script by repeatedly trying to connect. Once
-successful, it immediately closes the port, which causes the script to
-terminate.
-
-~~~scenario
-given a daemon helper shell script slow-start-daemon.py
-given there is no "slow-start-daemon.py" process
-when I try to start "./slow-start-daemon.py" as slow-daemon, on port 8888
-then starting the daemon succeeds
-when I stop background process slow-daemon
-then there is no "slow-start-daemon.py" process
-~~~
-
-~~~{#slow-start-daemon.py .file .python .numberLines}
-#!/usr/bin/env python3
-
-import socket
-import time
-
-time.sleep(2)
-
-s = socket.socket()
-s.bind(("127.0.0.1", 8888))
-s.listen()
-
-(conn, _) = s.accept()
-conn.recv(1)
-s.close()
-
-print("OK")
-~~~
-
-# Daemon never opens the intended port
-
-This scenario verifies that if the background process never starts
-listening on its port, the daemon library handles that correctly.
-
-~~~scenario
-given there is no "/bin/sleep 12765" process
-when I try to start "/bin/sleep 12765" as sleepyhead, on port 8888
-then starting daemon fails with "ConnectionRefusedError"
-then a process "/bin/sleep 12765" is running
-when I stop background process sleepyhead
-then there is no "/bin/sleep 12765" process
-~~~
-
-
-# Daemon stdout and stderr are retrievable
-
-Sometimes it's useful for the step functions to be able to retrieve
-the stdout or stderr of of the daemon, after it's started, or even
-after it's terminated. This scenario verifies that `lib/daemon` can do
-that.
-
-~~~scenario
-given a daemon helper shell script chatty-daemon.sh
-given there is no "chatty-daemon" process
-when I start "./chatty-daemon.sh" as a background process as chatty-daemon
-when daemon chatty-daemon has produced output
-when I stop background process chatty-daemon
-then there is no "chatty-daemon" process
-then daemon chatty-daemon stdout is "hi there\n"
-then daemon chatty-daemon stderr is "hola\n"
-~~~
-
-We make for the daemon to exit, to work around a race condition: if
-the test program retrieves the daemon's output too fast, it may not
-have had time to produce it yet.
-
-
-~~~{#chatty-daemon.sh .file .sh .numberLines}
-#!/bin/bash
-
-set -euo pipefail
-
-trap 'exit 0' TERM
-
-echo hola 1>&2
-echo hi there
-~~~
-
-# Can specify additional environment variables for daemon
-
-Some daemons are configured through their environment rather than configuration
-files. This scenario verifies that a step can set arbitrary variables in the
-daemon's environment.
-
-~~~scenario
-when I start "/usr/bin/env" as a background process as env, with environment {"custom_variable": "has a Value"}
-when daemon env has produced output
-when I stop background process env
-then daemon env stdout contains "custom_variable=has a Value"
-~~~
-
-~~~scenario
-given a daemon helper shell script env-with-port.py
-when I try to start "./env-with-port.py 8765" as env-with-port, on port 8765, with environment {"custom_variable": "1337"}
-when I stop background process env-with-port
-then daemon env-with-port stdout contains "custom_variable=1337"
-~~~
-
-~~~scenario
-given a daemon helper shell script env-with-port.py
-when I start "./env-with-port.py 8766" as a background process as another-env-with-port, on port 8766, with environment {"subplot2": "000"}
-when daemon another-env-with-port has produced output
-when I stop background process another-env-with-port
-then daemon another-env-with-port stdout contains "subplot2=000"
-~~~
-
-It's important that these new environment variables are not inherited by the
-steps that follow. To verify that, we run one more scenario which *doesn't* set
-any variables, but checks that none of the variables we mentioned above are
-present.
-
-~~~scenario
-when I start "/usr/bin/env" as a background process as env2
-when daemon env2 has produced output
-when I stop background process env2
-then daemon env2 stdout doesn't contain "custom_variable=has a Value"
-then daemon env2 stdout doesn't contain "custom_variable=1337"
-then daemon env2 stdout doesn't contain "subplot2=000"
-~~~
-
-~~~{#env-with-port.py .file .python .numberLines}
-#!/usr/bin/env python3
-
-import os
-import socket
-import sys
-import time
-
-for (key, value) in os.environ.items():
- print(f"{key}={value}")
-
-port = int(sys.argv[1])
-print(f"port is {port}")
-
-s = socket.socket()
-s.bind(("127.0.0.1", port))
-s.listen()
-
-(conn, _) = s.accept()
-conn.recv(1)
-s.close()
-~~~
-
-
----
-title: Acceptance criteria for the lib/daemon Subplot library
-author: The Subplot project
-bindings:
-- daemon.yaml
-template: python
-functions:
-- daemon.py
-- runcmd.py
-...
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.md b/share/python/lib/files.md
deleted file mode 100644
index 823c760..0000000
--- a/share/python/lib/files.md
+++ /dev/null
@@ -1,105 +0,0 @@
-# Introduction
-
-The [Subplot][] library `files` provides scenario steps and their
-implementations for managing files on the file system during tests.
-The library consists of a bindings file `lib/files.yaml` and
-implementations in Python in `lib/files.py`.
-
-[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 `files`
-library.
-
-# Create on-disk files from embedded files
-
-Subplot allows the source document to embed test files, and the
-`files` library provides steps to create real, on-disk files from
-the embedded files.
-
-~~~scenario
-given file hello.txt
-then file hello.txt exists
-and file hello.txt contains "hello, world"
-and file other.txt does not exist
-given file other.txt from hello.txt
-then file other.txt exists
-and files hello.txt and other.txt match
-and only files hello.txt, other.txt exist
-~~~
-
-~~~{#hello.txt .file .numberLines}
-hello, world
-~~~
-
-
-# File metadata
-
-These steps create files and manage their metadata.
-
-~~~scenario
-given file hello.txt
-when I remember metadata for file hello.txt
-then file hello.txt has same metadata as before
-
-when I write "yo" to file hello.txt
-then file hello.txt has different metadata from before
-~~~
-
-# File modification time
-
-These steps manipulate and test file modification times.
-
-~~~scenario
-given file foo.dat has modification time 1970-01-02 03:04:05
-then file foo.dat has a very old modification time
-
-when I touch file foo.dat
-then file foo.dat has a very recent modification time
-~~~
-
-
-# File contents
-
-These steps verify contents of files.
-
-~~~scenario
-given file hello.txt
-then file hello.txt contains "hello, world"
-and file hello.txt matches regex "hello, .*"
-and file hello.txt matches regex /hello, .*/
-~~~
-
-# Directories
-
-There are also a large number of directory based steps and some directory
-based behaviour available in creating files which are available in the files
-library.
-
-```scenario
-given a directory first
-then directory first exists
-and directory first is empty
-and directory second does not exist
-when I remove directory first
-then directory first does not exist
-when I create directory second
-then directory second exists
-and directory second is empty
-given file second/third/hello.txt from hello.txt
-then directory second is not empty
-and directory second/third exists
-and directory second/third is not empty
-when I remove directory second
-then directory second does not exist
-```
-
----
-title: Acceptance criteria for the files Subplot library
-author: The Subplot project
-template: python
-bindings:
-- files.yaml
-functions:
-- files.py
-...
diff --git a/share/python/lib/files.py b/share/python/lib/files.py
index fa219b4..8c2c3a7 100644
--- a/share/python/lib/files.py
+++ b/share/python/lib/files.py
@@ -1,3 +1,5 @@
+from time import strptime
+
import logging
import os
import re
@@ -5,21 +7,21 @@ import shutil
import time
-def files_create_from_embedded(ctx, filename=None):
- files_make_directory(ctx, path=os.path.dirname(filename) or ".")
+def files_create_from_embedded(ctx, embedded_file=None):
+ files_make_directory(ctx, path=os.path.dirname(embedded_file) or ".")
files_create_from_embedded_with_other_name(
- ctx, filename_on_disk=filename, embedded_filename=filename
+ ctx, filename_on_disk=embedded_file, embedded_file=embedded_file
)
def files_create_from_embedded_with_other_name(
- ctx, filename_on_disk=None, embedded_filename=None
+ ctx, filename_on_disk=None, embedded_file=None
):
get_file = globals()["get_file"]
files_make_directory(ctx, path=os.path.dirname(filename_on_disk) or ".")
with open(filename_on_disk, "wb") as f:
- f.write(get_file(embedded_filename))
+ f.write(get_file(embedded_file))
def files_create_from_text(ctx, filename=None, text=None):
@@ -106,27 +108,8 @@ def files_match(ctx, filename1=None, filename2=None):
assert_eq(data1, data2)
-def files_touch_with_timestamp(
- ctx,
- filename=None,
- year=None,
- month=None,
- day=None,
- hour=None,
- minute=None,
- second=None,
-):
- t = (
- int(year),
- int(month),
- int(day),
- int(hour),
- int(minute),
- int(second),
- -1,
- -1,
- -1,
- )
+def files_touch_with_timestamp(ctx, filename=None, mtime = None):
+ t = strptime(mtime, "%Y-%m-%d %H:%M:%S")
ts = time.mktime(t)
_files_touch(filename, ts)
diff --git a/share/python/lib/files.yaml b/share/python/lib/files.yaml
deleted file mode 100644
index f18b8cd..0000000
--- a/share/python/lib/files.yaml
+++ /dev/null
@@ -1,83 +0,0 @@
-- given: file {filename}
- function: files_create_from_embedded
- types:
- filename: file
-
-- given: file {filename_on_disk} from {embedded_filename}
- 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
-
-- when: I write "(?P<text>.*)" to file (?P<filename>\S+)
- regex: true
- function: files_create_from_text
-
-- when: I remember metadata for file {filename}
- function: files_remember_metadata
-
-- when: I touch file {filename}
- function: files_touch
-
-- then: file {filename} exists
- function: files_file_exists
-
-- then: file {filename} does not exist
- function: files_file_does_not_exist
-
-- then: only files (?P<filenames>.+) exist
- function: files_only_these_exist
- regex: true
-
-- then: file (?P<filename>\S+) contains "(?P<data>.*)"
- regex: true
- function: files_file_contains
-
-- then: file (?P<filename>\S+) matches regex /(?P<regex>.*)/
- regex: true
- function: files_file_matches_regex
-
-- then: file (?P<filename>\S+) matches regex "(?P<regex>.*)"
- regex: true
- function: files_file_matches_regex
-
-- then: files {filename1} and {filename2} match
- function: files_match
-
-- then: file {filename} has same metadata as before
- function: files_has_remembered_metadata
-
-- then: file {filename} has different metadata from before
- function: files_has_different_metadata
-
-- then: file {filename} has changed from before
- function: files_has_different_metadata
-
-- then: file {filename} has a very recent modification time
- function: files_mtime_is_recent
-
-- then: file {filename} has a very old modification time
- function: files_mtime_is_ancient
-
-- given: a directory {path}
- function: files_make_directory
-
-- when: I create directory {path}
- function: files_make_directory
-
-- when: I remove directory {path}
- function: files_remove_directory
-
-- then: directory {path} exists
- function: files_directory_exists
-
-- then: directory {path} does not exist
- function: files_directory_does_not_exist
-
-- then: directory {path} is empty
- function: files_directory_is_empty
-
-- then: directory {path} is not empty
- function: files_directory_is_not_empty
diff --git a/share/python/lib/runcmd.md b/share/python/lib/runcmd.md
deleted file mode 100644
index 5f99b2a..0000000
--- a/share/python/lib/runcmd.md
+++ /dev/null
@@ -1,214 +0,0 @@
-# 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
-~~~
-
-## Successful execution in a sub-directory
-
-~~~scenario
-given a directory xyzzy
-when I run, in xyzzy, /bin/pwd
-then exit code is 0
-then command is successful
-then stdout contains "/xyzzy"
-~~~
-
-## Failed execution
-
-~~~scenario
-when I try to run /bin/false
-then exit code is not 0
-and command fails
-~~~
-
-## Failed execution in a sub-directory
-
-~~~scenario
-given a directory xyzzy
-when I try to run, in xyzzy, /bin/false
-then exit code is not 0
-and command fails
-~~~
-
-# Check we can prepend to $PATH
-
-This scenario verifies that we can add a directory to the beginning of
-the PATH environment variable, so that we can have `runcmd` invoke a
-binary from our build tree rather than from system directories. This
-is especially useful for testing new versions of software that's
-already installed on the system.
-
-~~~scenario
-given executable script ls from ls.sh
-when I prepend . to PATH
-when I run ls
-then command is successful
-then stdout contains "custom ls, not system ls"
-~~~
-
-~~~{#ls.sh .file .sh .numberLines}
-#!/bin/sh
-echo "custom ls, not system ls"
-~~~
-
-# 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
-template: python
-bindings:
-- runcmd.yaml
-- runcmd_test.yaml
-- files.yaml
-functions:
-- runcmd.py
-- runcmd_test.py
-- files.py
-...
diff --git a/share/python/lib/runcmd.py b/share/python/lib/runcmd.py
index da6c3fd..c4a6a12 100644
--- a/share/python/lib/runcmd.py
+++ b/share/python/lib/runcmd.py
@@ -93,10 +93,10 @@ def runcmd_helper_srcdir_path(ctx):
# Step: This creates a helper script.
-def runcmd_helper_script(ctx, filename=None):
+def runcmd_helper_script(ctx, script=None):
get_file = globals()["get_file"]
- with open(filename, "wb") as f:
- f.write(get_file(filename))
+ with open(script, "wb") as f:
+ f.write(get_file(script))
#
diff --git a/share/python/lib/runcmd.yaml b/share/python/lib/runcmd.yaml
deleted file mode 100644
index a5119d8..0000000
--- a/share/python/lib/runcmd.yaml
+++ /dev/null
@@ -1,91 +0,0 @@
-# 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 run, in (?P<dirname>\S+), (?P<argv0>\S+)(?P<args>.*)
- regex: true
- function: runcmd_step_in
-
-- when: I try to run (?P<argv0>\S+)(?P<args>.*)
- regex: true
- 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
-
-# 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
diff --git a/share/python/lib/runcmd_test.py b/share/python/lib/runcmd_test.py
deleted file mode 100644
index 6aa435a..0000000
--- a/share/python/lib/runcmd_test.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import os
-
-
-def create_script_from_embedded(ctx, filename=None, embedded=None):
- files_create_from_embedded_with_other_name = globals()[
- "files_create_from_embedded_with_other_name"
- ]
-
- # Create the file.
- files_create_from_embedded_with_other_name(
- ctx, filename_on_disk=filename, embedded_filename=embedded
- )
-
- # Make the new file executable.
- os.chmod(filename, 0o755)
diff --git a/share/python/lib/runcmd_test.yaml b/share/python/lib/runcmd_test.yaml
deleted file mode 100644
index 8ade220..0000000
--- a/share/python/lib/runcmd_test.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-- given: "executable script {filename} from {embedded}"
- function: create_script_from_embedded
-
-- when: "I prepend {dirname} to PATH"
- 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
deleted file mode 100644
index 5fa4f45..0000000
--- a/share/rust/lib/files.yaml
+++ /dev/null
@@ -1,89 +0,0 @@
-# Bindings for the files steps
-# These bind the files step library for subplotlib
-
-- given: file {embedded_file}
- 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
- 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
- types:
- mtime: text
-
-- when: I write "(?P<text>.*)" to file (?P<filename>\S+)
- regex: true
- function: subplotlib::steplibrary::files::create_from_text
-
-- when: I remember metadata for file {filename}
- function: subplotlib::steplibrary::files::remember_metadata
-
-- when: I touch file {filename}
- function: subplotlib::steplibrary::files::touch
-
-- then: file {filename} exists
- function: subplotlib::steplibrary::files::file_exists
-
-- then: file {filename} does not exist
- function: subplotlib::steplibrary::files::file_does_not_exist
-
-- then: only files (?P<filenames>.+) exist
- 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
-
-- then: file (?P<filename>\S+) matches regex /(?P<regex>.*)/
- regex: true
- 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
-
-- then: files {filename1} and {filename2} match
- function: subplotlib::steplibrary::files::file_match
-
-- then: file {filename} has same metadata as before
- function: subplotlib::steplibrary::files::has_remembered_metadata
-
-- then: file {filename} has different metadata from before
- function: subplotlib::steplibrary::files::has_different_metadata
-
-- then: file {filename} has changed from before
- function: subplotlib::steplibrary::files::has_different_metadata
-
-- then: file {filename} has a very recent modification time
- function: subplotlib::steplibrary::files::mtime_is_recent
-
-- then: file {filename} has a very old modification time
- function: subplotlib::steplibrary::files::mtime_is_ancient
-
-- given: a directory {path}
- function: subplotlib::steplibrary::files::make_directory
-
-- when: I create directory {path}
- function: subplotlib::steplibrary::files::make_directory
-
-- when: I remove directory {path}
- function: subplotlib::steplibrary::files::remove_directory
-
-- then: directory {path} exists
- function: subplotlib::steplibrary::files::path_exists
-
-- then: directory {path} does not exist
- function: subplotlib::steplibrary::files::path_does_not_exist
-
-- then: directory {path} is empty
- function: subplotlib::steplibrary::files::path_is_empty
-
-- then: directory {path} is not empty
- function: subplotlib::steplibrary::files::path_is_not_empty
diff --git a/share/rust/lib/runcmd.yaml b/share/rust/lib/runcmd.yaml
deleted file mode 100644
index fc2db6b..0000000
--- a/share/rust/lib/runcmd.yaml
+++ /dev/null
@@ -1,97 +0,0 @@
-# Bindings for the runcmd steplibrary
-
-- given: helper script {script} for runcmd
- function: subplotlib::steplibrary::runcmd::helper_script
- types:
- script: file
-
-- given: srcdir is in the PATH
- function: subplotlib::steplibrary::runcmd::helper_srcdir_path
-
-- when: I run (?P<argv0>\S+)(?P<args>.*)
- regex: true
- 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
-
-- when: I try to run (?P<argv0>\S+)(?P<args>.*)
- regex: true
- 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
-
-# Steps to examine exit code of latest command.
-
-- then: exit code is {exit}
- function: subplotlib::steplibrary::runcmd::exit_code_is
- types:
- exit: int
-
-- then: exit code is not {exit}
- function: subplotlib::steplibrary::runcmd::exit_code_is_not
- types:
- exit: int
-
-- then: command is successful
- function: subplotlib::steplibrary::runcmd::exit_code_is_zero
-
-- then: command fails
- 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
-
-- then: 'stdout isn''t exactly "(?P<text>.*)"'
- regex: true
- function: subplotlib::steplibrary::runcmd::stdout_isnt
-
-- then: stderr is exactly "(?P<text>.*)"
- regex: true
- function: subplotlib::steplibrary::runcmd::stderr_is
-
-- then: 'stderr isn''t exactly "(?P<text>.*)"'
- regex: true
- 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
-
-- then: 'stdout doesn''t contain "(?P<text>.*)"'
- regex: true
- function: subplotlib::steplibrary::runcmd::stdout_doesnt_contain
-
-- then: stderr contains "(?P<text>.*)"
- regex: true
- function: subplotlib::steplibrary::runcmd::stderr_contains
-
-- then: 'stderr doesn''t contain "(?P<text>.*)"'
- regex: true
- 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
-
-- then: stdout doesn't match regex (?P<regex>.*)
- regex: true
- function: subplotlib::steplibrary::runcmd::stdout_doesnt_match_regex
-
-- then: stderr matches regex (?P<regex>.*)
- regex: true
- 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