- Basic structure
- Example group
- Example
- Evaluation
- Expectation
- Subjects
- Modifiers
- Matchers
satisfymatcher- stat matchers
be existmatcherbe filematcherbe directorymatcherbe empty filematcherbe empty directorymatcherbe symlinkmatcherbe pipematcherbe socketmatcherbe readablematcherbe writablematcherbe executablematcherbe block_devicematcherbe character_devicematcherhave setgidmatcherhave setuidmatcher
- status matchers
- string matchers
successfulmatcher- valid matchers
- variable matchers
- Helper
- Hooks
- Directive
- Special environment Variables
You can write a structured Example by using the DSL shown below:
| DSL | Description |
|---|---|
| ExampleGroup ... End | Define an example group. |
| Describe ... End | Synonym for ExampleGroup. |
| Context ... End | Synonym for ExampleGroup. |
Example groups are nestable.
| DSL | Description |
|---|---|
| Example ... End | Define an example. |
| It ... End | Synonym for Example. |
| Specify ... End | Synonym for Example. |
The line beginning with When is the evaluation.
| Evaluation | Description |
|---|---|
| When call | Call shell function without subshell. |
| When run | Run shell function or external command within a subshell. |
| When run command | Run external command (including non-shell scripts). |
| When run script | Run shell script by new process of the current shell. |
| When run source | Run shell script in the current shell by . command (aka source). |
When call <FUNCTION> [ARGUMENTS...]This is primarily designed for shell function calls. It is the recommended evaluation as a unit test. It does not use a subshell, therefore it is the fastest evaluation variant and you can assert variables.
When run <FUNCTION | COMMAND> [ARGUMENTS...]This is primarily designed for external command calls. The external command does not have to be a shell script. Even shell scripts are executed as external commands according to the shebang, so they are not covered by the coverage.
If a shell function is specified, it will be executed in a subshell. The slight advantage of
executing shell functions with run is that you can trap errors with set -e.
Unlike call, it does not cause an error, so you can assert the exit status.
Also, because of the execution in the subshell, the variables which change values in the function are restored once run finishes.
This is often a disadvantage, but tests of ShellSpec itself intentionally use run
because changing internal variables confuses ShellSpec's behavior.
If you want to assert variables with run, use the %preserve directive in function called by AfterRun hook.
It can preserve variables even if run exits the subshell.
When run command <COMMAND> [ARGUMENTS...]Run an external command explicitly. The external command does not have to be a shell script. Even shell scripts are executed as external commands according to the shebang, so they are not covered by the coverage.
When run script <SCRIPT> [ARGUMENTS...]Run the external shell script in the same shell as the currently running shell.
When run source <SCRIPT> [ARGUMENTS...]This is similar to run script, but simulates the running of shell
scripts using the . command instead of running directly.
The advantage over run script is that you can use Intercept to intercept
at any point in the external shell script.
This is useful for preparation testing and mocking with shell functions.
call |
run |
run command |
run script |
run source |
|
|---|---|---|---|---|---|
| Run in subshell | No | Yes | Yes | Yes | Yes |
| Target | function | function / command | command | shell script | shell script |
Stop with set -e |
No | Yes | - | Yes | Yes |
Catch exit |
No | Yes | - | Yes | Yes |
| Expectation Hooks | BeforeCall / AfterCall | BeforeRun / AfterRun | BeforeRun / AfterRun | BeforeRun / AfterRun | BeforeRun / AfterRun |
| Intercept | No | No | - | No | Yes |
| Coverage | Yes | Yes (function only) | No | Yes | Yes |
The line beginning with The is the evaluation. The subject or the modifier follows after The. And last is the matcher.
The [MODIFIER of...] <SUBJECT> should <MATCHER>
The [MODIFIER of...] <SUBJECT> should not <MATCHER>Assert <FUNCTION> [ARGUMENTS...]| Subject | Description |
|---|---|
| stdout / output | Use the stdout of Evaluation as subject. |
| line | Same as line NUMBER of stdout. |
| word | Same as word NUMBER of stdout. |
| stderr / error | Use the stderr of Evaluation as subject. |
| status | Use the status of Evaluation as subject. |
| path / file / directory | Use the alias resolved path as the subject. |
| value | Use the value as the subject. |
| function | Use the function name as the subject. |
| variable | Use the value of the variable as the subject. |
The stdout should equal "foo"
The output should equal "foo"The stderr should equal "foo"
The error should equal "foo"The status should be successWhen combined with line, stdout can be omitted.
The line 1 of stdout should equal foo
The line 1 should equal foo # stdout omittedWhen combined with word, stdout can be omitted.
The word 1 of stdout should equal foo
The word 1 should equal foo # stdout omittedPath data-file=/tmp/data.txt
The path data-file should existThe result of function foo should be successful
The result of "foo()" should be successful # shorthandThe value "foo" should equal "foo"I do not recommend using this subject as it may not generate clear
failure messages. Use the variable subject instead.
The variable var should equal "foo"| Modifier | Description |
|---|---|
| line | The specified line of the subject. |
| lines | The number of lines of the subject. |
| word | The specified word of the subject. |
| length | The length of the subject. |
| contents | The contents of the file as subject. |
| result | The result of the function as subject. |
The line 1 of stdout should equal "line1"The lines of stdout should equal 5The word 2 of stdout should equal "word2"The length of value "abcd" should equal 5The contents of file "/tmp/file.txt" should equal "temp data"get_version() {
# The result of the evaluation is passed as arguments
# $1: stdout, $2: stderr, $3: status
echo "$1" | grep -o '[0-9.]*' | head -1
}
When call echo "GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)"
The result of function get_version should equal "4.4.20"
The result of "get_version()" should equal "4.4.20" # shorthandcheck_version() {
# The result of the evaluation is passed as arguments
# $1: stdout, $2: stderr, $3: status
[ "$("$1" | grep -o '[0-9.]*' | head -1)" = "4.4.20" ]
}
When call echo "GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)"
The result of function check_version should be successful
The result of "check_version()" should be successful # shorthand| Matcher | Description |
|---|---|
| satisfy | The subject should satisfy <FUNCTION> |
satisfy <FUNCTION> [ARGUMENTS...]satisfy examples
value() {
# The subject is stored in the same variable name as the function name
test "${value:?}" "$1" "$2"
}
formula() {
value=${formula:?}
[ $(($1)) -eq 1 ]
}
When call echo "50"
The output should satisfy value -gt 10
The output should satisfy formula "10 <= value && value <= 100"the subject expected file path
| Matcher | Description |
|---|---|
| exist | The file should exist. |
| The file should exist. (deprecated) | |
| be file | The file should be a file. |
| be directory | The file should be a directory. |
| be empty file | The file should be an empty file. |
| be empty directory | The directory should be an empty directory. |
| be symlink | The file should be a symlink. |
| be pipe | The file should be a pipe. |
| be socket | The file should be a socket. |
| be readable | The file should be readable. |
| be writable | The file should be writable. |
| be executable | The file should be executable. |
| be block_device | The file should be a block device. |
| be character_device | The file should be a character device. |
| The file should have the setgid flag set. (deprecated) | |
| have setgid | The file should have the setgid flag set. |
| The file should have the setuid flag set. (deprecated) | |
| have setuid | The file should have the setuid flag set. |
The path /target/path should existor
The path /target/path should be existThe path /target/path should be fileThe path /target/path should be directory
The path /target/path should be dirThe path /target/path should be empty fileThe path /target/path should be empty directory
The path /target/path should be empty dirThe path /target/path should be symlinkThe path /target/path should be pipeThe path /target/path should be socketThe path /target/path should be readableThe path /target/path should be writableThe path /target/path should be executableThe path /target/path should be block_deviceThe path /target/path should be character_deviceThe path /target/path should have setgidThe path /target/path should have setuidthe subject expected status
| Matcher | Description |
|---|---|
| be success | The status should be success (0). |
| be failure | The status should be failure (1 - 255). |
The status should be successThe status should be failure| Matcher | Description |
|---|---|
equal <STRING>eq <STRING> |
The subject should equal <STRING> |
start with <STRING> |
The subject should start with <STRING> |
end with <STRING> |
The subject should end with <STRING> |
include <STRING> |
The subject should include <STRING> |
match pattern <PATTERN> |
The subject should match pattern <PATTERN> |
The output should equal <STRING>
The output should eq <STRING>The output should start with <STRING>The output should end with <STRING>The output should include <STRING>The output should match pattern <PATTERN>PATTERN examples
foo*foo?[fF]oo[!F]oo[a-z]foo|bar
Use with result modifier.
Plan to deprecate in the future.
| Matcher | Description |
|---|---|
| be valid number | The subject should be a valid number. |
| be valid funcname | The subject should be a valid funcname. |
the subject expect variable
| Matcher | Description |
|---|---|
| be defined | The variable should be defined (set). |
| be undefined | The variable should be undefined (unset). |
| be present | The variable should be present (non-zero length string). |
| be blank | The variable should be blank (unset or zero length string). |
| be exported | The variable should be exported. |
| be readonly | The variable should be readonly. |
The variable VAR should be definedThe variable VAR should be undefinedThe variable VAR should be presentThe variable VAR should be blankThe variable VAR should be exportedThe variable VAR should be readonly| DSL | Description |
|---|---|
Skip <REASON> |
Skip current block. |
Skip if <REASON> <FUNCTION> [ARGUMENTS...] |
Skip current block with conditional. |
Pending <REASON> |
Pending current block. |
| Todo | Define pending example |
| DSL | Description |
|---|---|
| Data[:raw] #|... End |
Define stdin data for evaluation (without expand variables). |
| Data:expand #|... End |
Define stdin data for evaluation (with expand variables). |
Data <FUNCTION> [ARGUMENTS...] |
Use function for stdin data for evaluation. |
Data "<STRING>"Data '<STRING>' |
Use string for stdin data for evaluation. |
Data < <FILE> |
Use file for stdin data for evaluation. |
NOTE: The Data helper can also be used with filters.
Data | tr 'abc' 'ABC' # comment
#|aaa
#|bbb
#|ccc
EndDescribe 'Data helper'
Example 'provide with Data helper block style'
Data
#|item1 123
#|item2 456
#|item3 789
End
When call awk '{total+=$2} END{print total}'
The output should eq 1368
End
End| DSL | Description |
|---|---|
| Parameters ... End | Define parameters (block style) |
| Parameters:block ... End | Same as Parameters |
Parameters:value [VALUES...] |
Define parameters (value style) |
| Parameters:matrix ... End | Define parameters (matrix style) |
| Parameters:dynamic ... End | Define parameters (dynamic style) |
NOTE: Multiple Parameters definitions are merged.
Describe 'example'
Parameters
"#1" 1 2 3
"#2" 1 2 3
End
Example "example $1"
When call echo "$(($2 + $3))"
The output should eq "$4"
End
EndParameters:value foo bar bazParameters:matrix
foo bar
1 2
# expanded as follows
# foo 1
# foo 2
# bar 1
# bar 2
EndParameters:dynamic
for i in 1 2 3; do
%data "#$i" 1 2 3
done
EndOnly %data directives can be used within a Parameters:dynamic block.
You can not call a function or access variables defined within the specfile.
You can refer to variables defined with %const.
| DSL | Description |
|---|---|
Include <NAME> |
Include other files. |
| Path File Dir |
Define a path alias. |
Intercept [NAMES...] |
Define an interceptor. |
Set [OPTION:<on | off>...] |
Set shell option before running each example. |
| Dump | Dump stdout, stderr and status for debugging. |
| DSL | Description |
|---|---|
| Before | Define a hook called before running each example. |
| After | Define a hook called after running each example. |
| BeforeAll | |
| AfterAll | |
| BeforeCall | |
| AfterCall | |
| BeforeRun | |
| AfterRun |
| Directive | Description |
|---|---|
| %const, % | Define a constant variable. |
| %text | Define a multiline texts to output to stdout. |
| %putsn, %= | Output arguments with the newline. |
| %puts, %- | Output arguments. |
| %logger | Output log message. |
% <VERNAME>: "<VALUE>"Use this with the When run evaluation.
ShellSpec provides special environment variables with prefix SHELLSPEC_.
They are useful for writing tests and extensions.
I'll try to avoid making breaking changes to these, but can't guarantee it.
There are many undocumented variables. You can use them at your own risk.
These variables can be overridden by the --env-from option, except for some
variables. This is an assumed usage, but has not been fully tested.
It is recommended to use it as read-only.
| Name | Description | Value |
|---|---|---|
| SHELLSPEC_ROOT | ShellSpec root directory | |
| SHELLSPEC_LIB | ShellSpec lib directory | ${SHELLSPEC_ROOT}/lib |
| SHELLSPEC_LIBEXEC | ShellSpec libexec directory | ${SHELLSPEC_ROOT}/libexec |
| SHELLSPEC_TMPDIR | Temporary directory | ${TMPDIR} or /tmp if not specified. |
| SHELLSPEC_TMPBASE | Temporary directory used by ShellSpec | ${SHELLSPEC_TMPDIR}/shellspec.${SHELLSPEC_UNIXTIME}.$$. |
| SHELLSPEC_WORKDIR | Temporary directory for each spec number | ${SHELLSPEC_TMPBASE}/${SHELLSPEC_SPEC_NO}. |
| SHELLSPEC_PROJECT_ROOT | Where .shellspec is located |
|
| Specfiles directory | ${SHELLSPEC_PROJECT_ROOT}/spec [depricated] |
|
| SHELLSPEC_HELPERDIR | spec_helper directory | ${SHELLSPEC_PROJECT_ROOT}/spec (default) |
| SHELLSPEC_LOAD_PATH | Load path of library | ${SHELLSPEC_SPECDIR}:${SHELLSPEC_LIB}:${SHELLSPEC_LIB}/formatters |
| SHELLSPEC_UNIXTIME | Unix Time when ShellSpec starts | |
| SHELLSPEC_SPECFILE | Current running specfile path | |
| SHELLSPEC_SPEC_NO | Current specfile number | |
| SHELLSPEC_GROUP_ID | Current group ID | e.g. 1-2 |
| SHELLSPEC_EXAMPLE_ID | Current example ID (including group ID) | e.g. 1-2-3 |
| SHELLSPEC_EXAMPLE_NO | Current serial number of example |