Skip to content

Latest commit

 

History

History
893 lines (671 loc) · 28.6 KB

references.md

File metadata and controls

893 lines (671 loc) · 28.6 KB

References

Basic structure

You can write a structured Example by using the DSL shown below:

Example group

DSL Description
ExampleGroup ... End Define an example group.
Describe ... End Synonym for ExampleGroup.
Context ... End Synonym for ExampleGroup.

ExampleGroup / Describe / Context

Example groups are nestable.

Example

DSL Description
Example ... End Define an example.
It ... End Synonym for Example.
Specify ... End Synonym for Example.

Example / It / Specify

Evaluation

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

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

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.

about calling shell function with run

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

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

When run script <SCRIPT> [ARGUMENTS...]

Run the external shell script in the same shell as the currently running shell.

When run source

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.

Comparison

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

Expectation

The ... should (not)

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

Assert <FUNCTION> [ARGUMENTS...]

Subjects

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.

stdout (output) subject

The stdout should equal "foo"
The output should equal "foo"

stderr (error) subject

The stderr should equal "foo"
The error should equal "foo"

status subject

The status should be success

line subject

When combined with line, stdout can be omitted.

The line 1 of stdout should equal foo
The line 1 should equal foo # stdout omitted

word subject

When combined with word, stdout can be omitted.

The word 1 of stdout should equal foo
The word 1 should equal foo # stdout omitted

path / file / directory subject

Path data-file=/tmp/data.txt
The path data-file should exist

function subject

The result of function foo should be successful
The result of "foo()" should be successful # shorthand

value subject

The 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.

variable subject

The variable var should equal "foo"

Modifiers

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.

line modifier

The line 1 of stdout should equal "line1"

lines modifier

The lines of stdout should equal 5

word modifier

The word 2 of stdout should equal "word2"

length modifier

The length of value "abcd" should equal 5

contents modifier

The contents of file "/tmp/file.txt" should equal "temp data"

result modifier

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" # shorthand
check_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

Matchers

satisfy matcher

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"

stat matchers

the subject expected file path

Matcher Description
exist The file should exist.
be 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.
has setgid The file should have the setgid flag set. (deprecated)
have setgid The file should have the setgid flag set.
has setuid The file should have the setuid flag set. (deprecated)
have setuid The file should have the setuid flag set.
exist matcher
The path /target/path should exist

or

The path /target/path should be exist
be file matcher
The path /target/path should be file
be directory matcher
The path /target/path should be directory
The path /target/path should be dir
be empty file matcher
The path /target/path should be empty file
be empty directory matcher
The path /target/path should be empty directory
The path /target/path should be empty dir
be symlink matcher
The path /target/path should be symlink
be pipe matcher
The path /target/path should be pipe
be socket matcher
The path /target/path should be socket
be readable matcher
The path /target/path should be readable
be writable matcher
The path /target/path should be writable
be executable matcher
The path /target/path should be executable
be block_device matcher
The path /target/path should be block_device
be character_device matcher
The path /target/path should be character_device
have setgid matcher
The path /target/path should have setgid
have setuid matcher
The path /target/path should have setuid

status matchers

the subject expected status

Matcher Description
be success The status should be success (0).
be failure The status should be failure (1 - 255).
be success matcher
The status should be success
be failure matcher
The status should be failure

string matchers

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>
equal matcher
The output should equal <STRING>
The output should eq <STRING>
start with matcher
The output should start with <STRING>
end with matcher
The output should end with <STRING>
include matcher
The output should include <STRING>
match pattern matcher
The output should match pattern <PATTERN>

PATTERN examples

  • foo*
  • foo?
  • [fF]oo
  • [!F]oo
  • [a-z]
  • foo|bar

successful matcher

Use with result modifier.

valid matchers

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.

variable matchers

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.
be defined matcher
The variable VAR should be defined
be undefined matcher
The variable VAR should be undefined
be present matcher
The variable VAR should be present
be blank matcher
The variable VAR should be blank
be exported matcher
The variable VAR should be exported
be readonly matcher
The variable VAR should be readonly

Helper

Skip / Pending

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

Skip

Skip if

Pending

Todo

Data

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
End

Data[:raw]

Describe '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

Data:expand

Data <FUNCTION>

Data "<STRING>"

Data < "<FILE>"

Parameters

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.

Parameters[:block]

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
End

Parameters:value

Parameters:value foo bar baz

Parameters:matrix

Parameters:matrix
  foo bar
  1 2

  # expanded as follows
  #   foo 1
  #   foo 2
  #   bar 1
  #   bar 2
End

Parameters:dynamic

Parameters:dynamic
  for i in 1 2 3; do
    %data "#$i" 1 2 3
  done
End

Only %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.

Others

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.

Include

Path / File / Dir

Intercept

Set

Dump

Hooks

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

Before / After

BeforeAll / AfterAll

BeforeCall / AfterCall

BeforeRun / AfterRun

Directive

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.

%const (%)

% <VERNAME>: "<VALUE>"

%text

%puts (%-) / %putsn (%=)

%preserve

Use this with the When run evaluation.

%logger

Special environment Variables

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
SHELLSPEC_SPECDIR 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