{"id":13495218,"url":"https://github.com/shellspec/shellspec","last_synced_at":"2025-05-15T21:08:14.397Z","repository":{"id":41276303,"uuid":"169286974","full_name":"shellspec/shellspec","owner":"shellspec","description":"A full-featured BDD unit testing framework for bash, ksh, zsh, dash and all POSIX shells","archived":false,"fork":false,"pushed_at":"2024-09-12T11:42:39.000Z","size":4879,"stargazers_count":1232,"open_issues_count":95,"forks_count":72,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-05-12T04:55:54.207Z","etag":null,"topics":["bash","bdd","coverage","dash","kcov","ksh","mock","posix-compliant","posix-sh","script","shell","shell-script","shellspec","tdd","test","testing","zsh"],"latest_commit_sha":null,"homepage":"https://shellspec.info","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shellspec.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ko1nksm"}},"created_at":"2019-02-05T18:04:57.000Z","updated_at":"2025-05-10T08:53:36.000Z","dependencies_parsed_at":"2024-01-03T04:12:59.300Z","dependency_job_id":"680617e7-695f-4b78-9947-3cf6b23c2315","html_url":"https://github.com/shellspec/shellspec","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellspec%2Fshellspec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellspec%2Fshellspec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellspec%2Fshellspec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellspec%2Fshellspec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shellspec","download_url":"https://codeload.github.com/shellspec/shellspec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254422790,"owners_count":22068679,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","bdd","coverage","dash","kcov","ksh","mock","posix-compliant","posix-sh","script","shell","shell-script","shellspec","tdd","test","testing","zsh"],"created_at":"2024-07-31T19:01:32.544Z","updated_at":"2025-05-15T21:08:13.433Z","avatar_url":"https://github.com/shellspec.png","language":"Shell","readme":"# ShellSpec: full-featured BDD unit testing framework\n\nShellSpec is a **full-featured [BDD](https://en.wikipedia.org/wiki/Behavior-driven_development) unit testing framework** for dash, bash, ksh, zsh and **all POSIX shells** that provides first-class features such as code coverage, mocking, parameterized test, parallel execution and more. It was developed as a dev/test tool for **cross-platform shell scripts and shell script libraries**. ShellSpec is a new modern testing framework released in 2019, but it's already stable enough. With lots of practical CLI features and simple yet powerful syntax, it provides you with a fun shell script test environment.\n\n[![Ubuntu](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/ubuntu-jammy.yml?label=Ubuntu\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/ubuntu-jammy.yml)\n[![macOS](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/macos-sonoma.yml?label=macOS\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/macos-sonoma.yml)\n[![FreeBSD](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/freebsd-14.yml?label=FreeBSD\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/freebsd-14.yml)\n[![NetBSD](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/netbsd-10.yml?label=NetBSD\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/netbsd-10.yml)\n[![OpenBSD](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/openbsd7.5.yml?label=OpenBSD\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/openbsd7.5.yml)\n[![DragonFlyBSD](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/dragonflybsd-6.4.yml?label=DragonFlyBSD\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/dragonflybsd-6.4.yml)\n[![Solaris11](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/solaris-11.4.yml?label=Solaris11\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/solaris-11.4.yml)\u003cbr\u003e\n[![gitbash](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/windows-gitbash.yml?label=Windows%20(gitbash)\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/windows-gitbash.yml)\n[![cygwin](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/windows-cygwin.yml?label=Windows%20(cygwin)\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/windows-cygwin.yml)\n[![msys](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/windows-msys.yml?label=Windows%20(msys)\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/windows-msys.yml)\n[![busybox](https://img.shields.io/github/actions/workflow/status/shellspec/shellspec/windows-busybox.yml?label=Windows%20(busybox)\u0026style=flat-square)](https://github.com/shellspec/shellspec/actions/workflows/windows-busybox.yml)\u003cbr\u003e\n[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/shellspec/shellspec?label=CodeFactor\u0026style=flat-square)](https://www.codefactor.io/repository/github/shellspec/shellspec)\n[![Code Climate](https://img.shields.io/codeclimate/coverage/shellspec/shellspec?label=CodeClimate\u0026style=flat-square)](https://codeclimate.com/github/shellspec/shellspec)\n[![Codecov](https://img.shields.io/codecov/c/github/shellspec/shellspec.svg?label=Codecov\u0026style=flat-square)](https://codecov.io/gh/shellspec/shellspec)\n[![Kcov](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fshellspec.github.io%2Fshellspec%2Fcoverage.json\u0026query=percent_covered\u0026label=Kcov\u0026suffix=%25\u0026style=flat-square)](https://shellspec.github.io/shellspec/)\n[![Docker Cloud Automated build](https://img.shields.io/docker/cloud/automated/shellspec/shellspec?style=flat-square\u0026label=DockerHub)](https://hub.docker.com/r/shellspec/shellspec)\n[![GitHub top language](https://img.shields.io/github/languages/top/shellspec/shellspec.svg?style=flat-square)](https://github.com/shellspec/shellspec/search?l=Shell)\n[![GitHub release](https://img.shields.io/github/release/shellspec/shellspec.svg?style=flat-square)](https://github.com/shellspec/shellspec/releases/latest)\n[![License](https://img.shields.io/github/license/shellspec/shellspec.svg?style=flat-square)](https://github.com/shellspec/shellspec/blob/master/LICENSE)\u003cbr\u003e\n[![bash](https://img.shields.io/badge/bash-\u0026ge;2.03-lightgrey.svg?style=flat)](https://www.gnu.org/software/bash/)\n[![bosh](https://img.shields.io/badge/bosh-\u0026ge;2018%2F10%2F07-lightgrey.svg?style=flat)](https://codeberg.org/schilytools/schilytools)\n[![busybox](https://img.shields.io/badge/busybox-\u0026ge;1.20.0-lightgrey.svg?style=flat)](https://www.busybox.net/)\n[![dash](https://img.shields.io/badge/dash-\u0026ge;0.5.4-lightgrey.svg?style=flat)](http://gondor.apana.org.au/~herbert/dash/)\n[![ksh](https://img.shields.io/badge/ksh-\u0026ge;93r-lightgrey.svg?style=flat)](https://github.com/ksh93/ksh)\n[![mksh](https://img.shields.io/badge/mksh-\u0026ge;R28-lightgrey.svg?style=flat)](http://www.mirbsd.org/mksh.htm)\n[![posh](https://img.shields.io/badge/posh-\u0026ge;0.3.14-lightgrey.svg?style=flat)](https://salsa.debian.org/clint/posh)\n[![yash](https://img.shields.io/badge/yash-\u0026ge;2.29-lightgrey.svg?style=flat)](https://magicant.github.io/yash/)\n[![zsh](https://img.shields.io/badge/zsh-\u0026ge;3.1.9-lightgrey.svg?style=flat)](https://www.zsh.org/)\n\n----\n\n**Version 0.28.0** has a lot of enhancements in the CLI. It is basically compatible, but there are some changes that you need to be aware of. See [Migration Guide to Version 0.28.0](https://github.com/shellspec/shellspec/wiki/Migration-Guide-to-Version-0.28.0) for details.\n\n----\n\n**Thank you for your interest in ShellSpec. Please visit 🚩[the official website](https://shellspec.info/) to know the impressive features!**\n\nLet's have fun testing your shell scripts! (Try [Online Demo](https://shellspec.info/demo) on your browser).\n\n[![demo](docs/demo.gif)](https://shellspec.info/demo)\n\n[![Coverage report](docs/coverage.png)](https://circleci.com/api/v1.1/project/github/shellspec/shellspec/latest/artifacts/0/coverage/index.html?branch=master)\n\n**Latest Update.**\n\nSee [CHANGELOG.md](CHANGELOG.md)\n\nNOTE: This documentation contains unreleased features. Check them in the changelog.\n\n----\n\n## Table of Contents \u003c!-- omit in toc --\u003e\n\n- [Supported shells and platforms](#supported-shells-and-platforms)\n- [Requirements](#requirements)\n- [Installation](#installation)\n  - [Web installer (for developers)](#web-installer-for-developers)\n  - [Package manager](#package-manager)\n  - [Manual installation](#manual-installation)\n  - [Distribution archive (runtime only)](#distribution-archive-runtime-only)\n- [Tutorial](#tutorial)\n- [ShellSpec CLI](#shellspec-cli)\n  - [runs specfile using `/bin/sh` by default](#runs-specfile-using-binsh-by-default)\n  - [command options](#command-options)\n- [Project directory](#project-directory)\n  - [Typical directory structure](#typical-directory-structure)\n  - [Options file](#options-file)\n  - [`.shellspec` - project options file](#shellspec---project-options-file)\n  - [`.shellspec-local` - user custom options file](#shellspec-local---user-custom-options-file)\n  - [`.shellspec-basedir` - specfile execution base directory](#shellspec-basedir---specfile-execution-base-directory)\n  - [`.shellspec-quick.log` - quick execution log](#shellspec-quicklog---quick-execution-log)\n  - [`report/` - report file directory](#report---report-file-directory)\n  - [`coverage/` - coverage reports directory](#coverage---coverage-reports-directory)\n  - [`spec/` - (default) specfiles directory](#spec---default-specfiles-directory)\n  - [\\\u003cHELPERDIR\\\u003e (default: `spec/`)](#helperdir-default-spec)\n    - [`spec_helper.sh` - (default) helper file for specfile](#spec_helpersh---default-helper-file-for-specfile)\n    - [`banner[.md]` - banner file displayed at test execution](#bannermd---banner-file-displayed-at-test-execution)\n    - [`support/` - directory for support files](#support---directory-for-support-files)\n      - [`bin` - directory for support commands](#bin---directory-for-support-commands)\n- [Specfile (test file)](#specfile-test-file)\n  - [Example](#example)\n  - [About DSL](#about-dsl)\n  - [Execution directory](#execution-directory)\n  - [Embedded shell scripts](#embedded-shell-scripts)\n  - [Translation process](#translation-process)\n  - [Syntax formatter (`altshfmt`)](#syntax-formatter-altshfmt)\n- [DSL syntax](#dsl-syntax)\n  - [Basic structure](#basic-structure)\n    - [`Describe`, `Context`, `ExampleGroup` - example group block](#describe-context-examplegroup---example-group-block)\n    - [`It`, `Specify`, `Example` - example block](#it-specify-example---example-block)\n    - [`Todo` - one liner empty example](#todo---one-liner-empty-example)\n    - [`When` - evaluation](#when---evaluation)\n      - [`call` - call a shell function (without subshell)](#call---call-a-shell-function-without-subshell)\n      - [`run` - run a command (within subshell)](#run---run-a-command-within-subshell)\n        - [`command` - runs an external command](#command---runs-an-external-command)\n        - [`script` - runs a shell script](#script---runs-a-shell-script)\n        - [`source` - runs a script by `.` (dot) command](#source---runs-a-script-by--dot-command)\n      - [About executing aliases](#about-executing-aliases)\n    - [`The` - expectation](#the---expectation)\n      - [Subjects](#subjects)\n      - [Modifiers](#modifiers)\n      - [Matchers](#matchers)\n      - [Language chains](#language-chains)\n    - [`Assert` - expectation for custom assertion](#assert---expectation-for-custom-assertion)\n  - [Pending, skip and focus](#pending-skip-and-focus)\n    - [`Pending` - pending example](#pending---pending-example)\n    - [`Skip` - skip example](#skip---skip-example)\n      - [`if` - conditional skip](#if---conditional-skip)\n    - ['x' prefix for example group and example](#x-prefix-for-example-group-and-example)\n      - [`xDescribe`, `xContext`, `xExampleGroup` - skipped example group](#xdescribe-xcontext-xexamplegroup---skipped-example-group)\n      - [`xIt`, `xSpecify`, `xExample` - skipped example](#xit-xspecify-xexample---skipped-example)\n    - ['f' prefix for example group and example](#f-prefix-for-example-group-and-example)\n      - [`fDescribe`, `fContext`, `fExampleGroup` - focused example group](#fdescribe-fcontext-fexamplegroup---focused-example-group)\n      - [`fIt`, `fSpecify`, `fExample` - focused example](#fit-fspecify-fexample---focused-example)\n    - [About temporary pending and skip](#about-temporary-pending-and-skip)\n  - [Hooks](#hooks)\n    - [`BeforeEach` (`Before`), `AfterEach` (`After`) - example hook](#beforeeach-before-aftereach-after---example-hook)\n    - [`BeforeAll`, `AfterAll` - example group hook](#beforeall-afterall---example-group-hook)\n    - [`BeforeCall`, `AfterCall` - call evaluation hook](#beforecall-aftercall---call-evaluation-hook)\n    - [`BeforeRun`, `AfterRun` - run evaluation hook](#beforerun-afterrun---run-evaluation-hook)\n    - [Pitfalls](#pitfalls)\n  - [Helpers](#helpers)\n    - [`Dump` - dump stdout, stderr, and status for debugging](#dump---dump-stdout-stderr-and-status-for-debugging)\n    - [`Include` - include a script file](#include---include-a-script-file)\n    - [`Set` - set shell options](#set---set-shell-options)\n    - [`Path`, `File`, `Dir` - path alias](#path-file-dir---path-alias)\n    - [`Data` - pass data as stdin to evaluation](#data---pass-data-as-stdin-to-evaluation)\n    - [`Parameters` - parameterized example](#parameters---parameterized-example)\n    - [`Mock` - create a command-based mock](#mock---create-a-command-based-mock)\n    - [`Intercept` - create an intercept point](#intercept---create-an-intercept-point)\n- [Directives](#directives)\n  - [`%const` (`%`) - constant definition](#const----constant-definition)\n  - [`%text` - embedded text](#text---embedded-text)\n  - [`%puts` (`%-`), `%putsn` (`%=`) - output a string (with newline)](#puts---putsn----output-a-string-with-newline)\n  - [`%printf` - alias for printf](#printf---alias-for-printf)\n  - [`%sleep` - alias for sleep](#sleep---alias-for-sleep)\n  - [`%preserve` - preserve variables](#preserve---preserve-variables)\n  - [`%logger` - debug output](#logger---debug-output)\n  - [`%data` - define parameter](#data---define-parameter)\n- [Mocking](#mocking)\n  - [Function-based mock](#function-based-mock)\n  - [Command-based mock](#command-based-mock)\n- [Support commands](#support-commands)\n  - [Execute the actual command within a mock function](#execute-the-actual-command-within-a-mock-function)\n  - [Make mock not mandatory in sandbox mode](#make-mock-not-mandatory-in-sandbox-mode)\n  - [Resolve command incompatibilities](#resolve-command-incompatibilities)\n- [Tagging](#tagging)\n- [About testing external commands](#about-testing-external-commands)\n- [How to test a single file shell script](#how-to-test-a-single-file-shell-script)\n  - [Using `run script`](#using-run-script)\n  - [Using `run source`](#using-run-source)\n  - [Testing shell functions](#testing-shell-functions)\n    - [`__SOURCED__`](#__sourced__)\n  - [Intercepting](#intercepting)\n    - [`Intercept`](#intercept)\n    - [`test || __() { :; }`](#test--__---)\n    - [`__`](#__)\n- [spec\\_helper](#spec_helper)\n  - [`\u003cmodule\u003e_precheck`](#module_precheck)\n    - [`minimum_version`](#minimum_version)\n    - [`error`, `warn`, `info`](#error-warn-info)\n    - [`abort`](#abort)\n    - [`setenv`, `unsetenv`](#setenv-unsetenv)\n    - [environment variables](#environment-variables)\n  - [`\u003cmodule\u003e_loaded`](#module_loaded)\n  - [`\u003cmodule\u003e_configure`](#module_configure)\n    - [`import`](#import)\n    - [`before_each`, `after_each`](#before_each-after_each)\n    - [`before_all`, `after_all`](#before_all-after_all)\n- [Self-executable specfile](#self-executable-specfile)\n- [Use with Docker](#use-with-docker)\n- [Extension](#extension)\n  - [Custom subject, modifier and matcher](#custom-subject-modifier-and-matcher)\n- [Code Coverage](#code-coverage)\n  - [Supported shells](#supported-shells)\n  - [Measurement target](#measurement-target)\n  - [Coverage report](#coverage-report)\n- [For developers](#for-developers)\n  - [Subprojects](#subprojects)\n    - [ShellMetrics - Cyclomatic Complexity Analyzer for shell scripts](#shellmetrics---cyclomatic-complexity-analyzer-for-shell-scripts)\n    - [ShellBench - A benchmark utility for POSIX shell comparison](#shellbench---a-benchmark-utility-for-posix-shell-comparison)\n    - [altshfmt - AltSH (alternative shell script) formatter](#altshfmt---altsh-alternative-shell-script-formatter)\n  - [Related projects](#related-projects)\n    - [getoptions - An elegant option parser and generator for shell scripts](#getoptions---an-elegant-option-parser-and-generator-for-shell-scripts)\n    - [readlinkf - readlink -f implementation for shell scripts](#readlinkf---readlink--f-implementation-for-shell-scripts)\n    - [portable-echo - Portable echo shell function for POSIX compliant shells](#portable-echo---portable-echo-shell-function-for-posix-compliant-shells)\n  - [Inspired frameworks](#inspired-frameworks)\n  - [Contributions](#contributions)\n\n## Supported shells and platforms\n\n- \u003ccode\u003e[bash][bash]\u003c/code\u003e_\u003e=2.03_, \u003ccode\u003e[bosh/pbosh][bosh]\u003c/code\u003e_\u003e=2018/10/07_, \u003ccode\u003e[posh][posh]\u003c/code\u003e_\u003e=0.3.14_, \u003ccode\u003e[yash][yash]\u003c/code\u003e_\u003e=2.29_, \u003ccode\u003e[zsh][zsh]\u003c/code\u003e_\u003e=3.1.9_\n- \u003ccode\u003e[dash][dash]\u003c/code\u003e_\u003e=0.5.4_, \u003ccode\u003e[busybox][busybox] ash\u003c/code\u003e_\u003e=1.20.0_, \u003ccode\u003e[busybox-w32][busybox-w32]\u003c/code\u003e, \u003ccode\u003e[GWSH][gwsh]\u003c/code\u003e_\u003e=20190627_\n- \u003ccode\u003eksh88\u003c/code\u003e, \u003ccode\u003e[ksh93][ksh93]\u003c/code\u003e_\u003e=93s_, \u003ccode\u003e[ksh2020][ksh2020]\u003c/code\u003e, \u003ccode\u003e[mksh/lksh][mksh]\u003c/code\u003e_\u003e=R28_, \u003ccode\u003e[pdksh][pdksh]\u003c/code\u003e_\u003e=5.2.14_\n- \u003ccode\u003e[FreeBSD sh][freebsdsh]\u003c/code\u003e, \u003ccode\u003e[NetBSD sh][netbsdsh]\u003c/code\u003e, \u003ccode\u003e[NetBSD ksh][netbsdksh]\u003c/code\u003e, \u003ccode\u003e[OpenBSD ksh][openbsdksh]\u003c/code\u003e, \u003ccode\u003e[loksh][loksh]\u003c/code\u003e, \u003ccode\u003e[oksh][oksh]\u003c/code\u003e\n\n[bash]: https://www.gnu.org/software/bash/\n[bosh]: http://schilytools.sourceforge.net/bosh.html\n[busybox]: https://www.busybox.net/\n[busybox-w32]: https://frippery.org/busybox/\n[dash]: http://gondor.apana.org.au/~herbert/dash/\n[gwsh]: https://github.com/hvdijk/gwsh\n[ksh93]: http://kornshell.org\n[ksh2020]: https://github.com/ksh-community/ksh\n[mksh]: http://www.mirbsd.org/mksh.htm\n[posh]: https://salsa.debian.org/clint/posh\n[yash]: https://yash.osdn.jp/\n[zsh]: https://www.zsh.org/\n[netbsdsh]: http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/sh/\n[netbsdksh]: http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/ksh/\n[freebsdsh]: https://www.freebsd.org/cgi/man.cgi?sh(1)\n[openbsdksh]: https://man.openbsd.org/ksh.1\n[pdksh]: https://web.archive.org/web/20160918190548/http://www.cs.mun.ca:80/~michael/pdksh/\n[loksh]: https://github.com/dimkr/loksh\n[oksh]: https://github.com/ibara/oksh\n\n| Platform                                                         | Test                                               |\n| ---------------------------------------------------------------- | -------------------------------------------------- |\n| Linux (Debian, Ubuntu, Fedora, CentOS, Alpine, Busybox, OpenWrt) | [GitHub Actions][Actions] or [Docker][Docker]      |\n| macOS (Default installed shells, Homebrew)                       | [GitHub Actions][Actions]                          |\n| Windows (Git bash, msys2, cygwin, busybox-w32, WSL)              | [GitHub Actions][Actions]                          |\n| BSD (FreeBSD, OpenBSD, NetBSD)                                   | [Cirrus CI][CirrusCI] (FreeBSD) or Manual (Others) |\n| Unix (Solaris, AIX)                                              | Manual only                                        |\n\n[Actions]: https://github.com/shellspec/shellspec/actions\n[CirrusCI]: https://cirrus-ci.com/github/shellspec/shellspec\n[Docker]: dockerfiles\n\n[Tested version details](docs/shells.md)\n\n## Requirements\n\n### POSIX-compliant commands \u003c!-- omit in toc --\u003e\n\nShellSpec uses shell built-in commands and only few basic [POSIX-compliant commands][utilities] to\nsupport wide range of environments (except `kcov` for optional code coverage).\n\n[utilities]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html\n\nCurrently used external (not shell builtins) commands:\n\n- `cat`, `date`, `env`, `ls`, `mkdir`, `od` (or not POSIX `hexdump`), `rm`, `sleep`, `sort`, `time`\n- `ps` (use to auto-detect shells in environments that don't implement procfs)\n- `ln`, `mv` (use only when generating coverage report)\n- `kill`, `printf` (most shells except some are built-in)\n\n## Installation\n\n### Web installer (for developers)\n\n#### Install the latest release version \u003c!-- omit in toc --\u003e\n\n```sh\ncurl -fsSL https://git.io/shellspec | sh\n```\n\nor\n\n```sh\nwget -O- https://git.io/shellspec | sh\n```\n\nNOTE: `https://git.io/shellspec` is redirected to [install.sh](https://github.com/shellspec/shellspec/raw/master/install.sh)\n\nThe installation using the web installer is mainly intended for development use.\nFor CI, it is recommended to use a specific version (tag) in git or archives to avoid unexpected failures.\n\n\u003cdetails\u003e\n\u003csummary\u003eAdvanced installation / upgrade\u003c/summary\u003e\n\n#### Automatic installation \u003c!-- omit in toc --\u003e\n\n```sh\ncurl -fsSL https://git.io/shellspec | sh -s -- --yes\n```\n\n#### Install the specified version \u003c!-- omit in toc --\u003e\n\n```sh\ncurl -fsSL https://git.io/shellspec | sh -s 0.19.1\n```\n\n#### Upgrade to the latest release version \u003c!-- omit in toc --\u003e\n\n```sh\ncurl -fsSL https://git.io/shellspec | sh -s -- --switch\n```\n\n#### Switch to the specified version \u003c!-- omit in toc --\u003e\n\n```sh\ncurl -fsSL https://git.io/shellspec | sh -s 0.18.0 --switch\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eUninstall\u003c/summary\u003e\n\n#### How to uninstall \u003c!-- omit in toc --\u003e\n\n1. Delete the ShellSpec executable file [default: `$HOME/.local/bin/shellspec`].\n2. Delete the ShellSpec installation directory [default: `$HOME/.local/lib/shellspec`].\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eOther usage\u003c/summary\u003e\n\n### Other usage \u003c!-- omit in toc --\u003e\n\n```console\n$ curl -fsSL https://git.io/shellspec | sh -s -- --help\nUsage: [sudo] ./install.sh [VERSION] [OPTIONS...]\n  or : wget -O- https://git.io/shellspec | [sudo] sh\n  or : wget -O- https://git.io/shellspec | [sudo] sh -s -- [OPTIONS...]\n  or : wget -O- https://git.io/shellspec | [sudo] sh -s VERSION [OPTIONS...]\n  or : curl -fsSL https://git.io/shellspec | [sudo] sh\n  or : curl -fsSL https://git.io/shellspec | [sudo] sh -s -- [OPTIONS...]\n  or : curl -fsSL https://git.io/shellspec | [sudo] sh -s VERSION [OPTIONS...]\n\nVERSION:\n  Specify install version and method\n\n  e.g\n    1.0.0           Install 1.0.0 from git\n    master          Install master from git\n    1.0.0.tar.gz    Install 1.0.0 from tar.gz archive\n    .               Install from local directory\n\nOPTIONS:\n  -p, --prefix PREFIX   Specify prefix                 [default: $HOME/.local]\n  -b, --bin BIN         Specify bin directory          [default: \u003cPREFIX\u003e/bin]\n  -d, --dir DIR         Specify installation directory [default: \u003cPREFIX\u003e/lib/shellspec]\n  -s, --switch          Switch version (requires installation via git)\n  -l, --list            List available versions (tags)\n      --pre             Include pre-release\n      --fetch FETCH     Force command to use when installing from archive (curl or wget)\n  -y, --yes             Automatic yes to prompts\n  -h, --help            You're looking at it\n```\n\n\u003c/details\u003e\n\n### Package manager\n\n\u003cdetails\u003e\n\u003csummary\u003eArch Linux\u003c/summary\u003e\n\nInstallation on Arch Linux from the AUR [ShellSpec package](https://aur.archlinux.org/packages/shellspec/) using `aura`:\n\n```console\n# Install the latest stable version\n$ aura -A shellspec\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eHomebrew / Linuxbrew\u003c/summary\u003e\n\n```console\n# Install the latest stable version\n$ brew tap shellspec/shellspec\n$ brew install shellspec\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003ebasher / bpkg\u003c/summary\u003e\n\nInstallation with [basher](https://github.com/basherpm/basher)\n\n**The officially supported version is ShellSpec 0.19.1 and later.**\n\n```console\n# Install from master branch\n$ basher install shellspec/shellspec\n\n# To specify a version (example: 0.19.1)\n$ basher install shellspec/shellspec@0.19.1\n```\n\nInstallation with [bpkg](https://github.com/bpkg/bpkg)\n\n**The officially supported version is ShellSpec 0.19.1 and later.**\n\n```console\n# Install from master branch\n$ bpkg install shellspec/shellspec\n\n# To specify a version (example: 0.19.1)\n$ bpkg install shellspec/shellspec@0.19.1\n```\n\n\u003c/details\u003e\n\n### Manual installation\n\n\u003cdetails\u003e\n\u003csummary\u003egit / archive (source code)\u003c/summary\u003e\n\nDownload from git or archive and create a symbolic link.\n\nFrom git\n\n```console\n$ cd /SOME/WHERE/TO/INSTALL\n$ git clone https://github.com/shellspec/shellspec.git\n\n$ ln -s /SOME/WHERE/TO/INSTALL/shellspec/shellspec /EXECUTABLE/PATH/\n```\n\nFrom archive\n\n```console\n$ cd /SOME/WHERE/TO/INSTALL\n$ wget https://github.com/shellspec/shellspec/archive/{VERSION}.tar.gz\n$ tar xzvf shellspec-{VERSION}.tar.gz\n\n$ ln -s /SOME/WHERE/TO/INSTALL/shellspec-{VERSION}/shellspec /EXECUTABLE/PATH/\n```\n\nExecutable path: e.g. `/usr/local/bin/`, `$HOME/bin/`\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eUse make instead of symbolic link creation\u003c/summary\u003e\n\nDownload from git or archive and use `make` command.\n\n**How to install.**\n\nInstall to `/usr/local/bin` and `/usr/local/lib`\n\n```sh\nsudo make install\n```\n\nInstall to `$HOME/bin` and `$HOME/lib`\n\n```sh\nmake install PREFIX=$HOME\n```\n\n**How to uninstall.**\n\n```sh\nsudo make uninstall\n```\n\n```sh\nmake uninstall PREFIX=$HOME\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eFor environments that do not support symbolic links\u003c/summary\u003e\n\nDownload from git or archive and create the following `shellspec` file instead of the symbolic link.\n\n```console\n$ cat\u003c\u003c'HERE'\u003e/EXECUTABLE/PATH/shellspec\n#!/bin/sh\nexec /SOME/WHERE/TO/INSTALL/shellspec/shellspec \"$@\"\nHERE\n$ chmod +x /EXECUTABLE/PATH/shellspec\n```\n\n\u003c/details\u003e\n\n### Distribution archive (runtime only)\n\nSee [Releases](https://github.com/shellspec/shellspec/releases) page if you want to download distribution archive.\n\n## Tutorial\n\n**Just create your project directory and run `shellspec --init` to setup your project**\n\n```console\n# Create your project directory, for example \"hello\".\n$ mkdir hello\n$ cd hello\n\n# Initialize\n$ shellspec --init\n  create   .shellspec\n  create   spec/spec_helper.sh\n\n# Write your first specfile (of course you can use your favorite editor)\n$ cat\u003c\u003c'HERE'\u003espec/hello_spec.sh\nDescribe 'hello.sh'\n  Include lib/hello.sh\n  It 'says hello'\n    When call hello ShellSpec\n    The output should equal 'Hello ShellSpec!'\n  End\nEnd\nHERE\n\n# Create lib/hello.sh\n$ mkdir lib\n$ touch lib/hello.sh\n\n# It will fail because the hello function is not implemented.\n$ shellspec\n\n# Write hello function\n$ cat\u003c\u003c'HERE'\u003elib/hello.sh\nhello() {\n  echo \"Hello ${1}!\"\n}\nHERE\n\n# It will success!\n$ shellspec\n```\n\n## ShellSpec CLI\n\n### runs specfile using `/bin/sh` by default\n\nShellSpec CLI runs specfiles with the shell running `shellspec`.\nUsually it is `/bin/sh` that is the shebang of `shellspec`. If you run `bash shellspec`, it will be bash.\n`Include` files from specfile will be executed in the same shell as well.\n\nThe purpose of this specification is to allow ShellSpec to easily change multiple types of shells\nand enable the development of cross-platform shell scripts that support multiple shells and environments.\n\nIf you want to test with a specific shell, use the `-s` (`--shell`) option.\nYou can specify the default shell in the `.shellspec` file.\n\nNOTE: If you execute a **shell script file** (not a shell function) from within the specfile,\nits shebang will be respected. Because in that case, it will be run as an external command.\nThe `-s` (`--shell`) option also has no effect.\nIf you are testing a external shell script file, you can use `When run script` or `When run source`.\nThese ignore the shebang of external shell script file and run in the same shell that runs specfile.\n\n### command options\n\nNOTE: Since version 0.28.0, [getoptions](https://github.com/ko1nksm/getoptions) is used to parse options,\nso all POSIX and GNU compatible option syntax can be used. For example, you can abbreviate a long option.\n\nSee more info: [ShellSpec CLI](docs/cli.md)\n\n```console\n$ shellspec -h\nUsage: shellspec [ -c ] [-C \u003cdirectory\u003e] [options...] [files or directories...]\n\n  Using + instead of - for short options causes reverses the meaning\n\n    -s, --shell SHELL               Specify a path of shell [default: \"auto\" (the shell running shellspec)]\n        --require MODULE            Require a MODULE (shell script file)\n    -O, --options PATH              Specify the path to an additional options file\n    -I, --load-path PATH            Specify PATH to add to $SHELLSPEC_LOAD_PATH (may be used more than once)\n        --helperdir DIRECTORY       The directory to load helper files (spec_helper.sh, etc) [default: \"spec\"]\n        --path PATH                 Set PATH environment variable at startup\n        --{no-}sandbox              Force the use of the mock instead of the actual command\n        --sandbox-path PATH         Make PATH the sandbox path instead of empty [default: empty]\n        --execdir @LOCATION[/DIR]   Specify the execution directory of each specfile | [default: @project]\n    -e, --env NAME[=VALUE]          Set environment variable\n        --env-from ENV-SCRIPT       Set environment variable from shell script file\n    -w, --{no-}warning-as-failure   Treat warning as failure [default: enabled]\n        --{no-}fail-fast[=COUNT]    Abort the run after first (or COUNT) of failures [default: disabled]\n        --{no-}fail-no-examples     Fail if no examples found [default: disabled]\n        --{no-}fail-low-coverage    Fail on low coverage [default: disabled]\n        --failure-exit-code CODE    Override the exit code used when there are failing specs [default: 101]\n        --error-exit-code CODE      Override the exit code used when there are fatal errors [default: 102]\n    -p, --{no-}profile              Enable profiling and list the slowest examples [default: disabled]\n        --profile-limit N           List the top N slowest examples [default: 10]\n        --{no-}boost                Increase the CPU frequency to boost up testing speed [default: disabled]\n        --log-file LOGFILE          Log file for %logger directive and trace [default: \"/dev/tty\"]\n        --tmpdir TMPDIR             Specify temporary directory [default: $TMPDIR, $TMP or \"/tmp\"]\n        --keep-tmpdir               Do not cleanup temporary directory [default: disabled]\n\n  The following options must be specified before other options and cannot be specified in the options file\n\n    -c, --chdir                     Change the current directory to the first path of arguments at the start\n    -C, --directory DIRECTORY       Change the current directory at the start\n\n  **** Execution ****\n\n    -q, --{no-}quick                Run not-passed examples if it exists, otherwise run all [default: disabled]\n    -r, --repair, --only-failures   Run failure examples only (Depends on quick mode)\n    -n, --next-failure              Run failure examples and abort on first failure (Depends on quick mode)\n    -j, --jobs JOBS                 Number of parallel jobs to run [default: 0 (disabled)]\n        --random TYPE[:SEED]        Run examples by the specified random type | \u003c[none]\u003e [specfiles] [examples]\n    -x, --xtrace                    Run examples with trace output of evaluation enabled [default: disabled]\n    -X, --xtrace-only               Run examples with trace output only enabled [default: disabled]\n        --dry-run                   Print the formatter output without running any examples [default: disabled]\n\n  **** Output ****\n\n        --{no-}banner               Show banner if exist \"\u003cHELPERDIR\u003e/banner[.md]\" [default: enabled]\n        --reportdir DIRECTORY       Output directory of the report [default: \"report\"]\n    -f, --format FORMATTER          Choose a formatter for display | \u003c[p]\u003e [d] [t] [j] [f] [null] [debug]\n    -o, --output FORMATTER          Choose a generator(s) to generate a report file(s) [default: none]\n        --{no-}color                Enable or disable color [default: enabled if the output is a TTY]\n        --skip-message VERBOSITY    Mute skip message | \u003c[verbose]\u003e [moderate] [quiet]\n        --pending-message VERBOSITY Mute pending message | \u003c[verbose]\u003e [quiet]\n        --quiet                     Equivalent of --skip-message quiet --pending-message quiet\n        --(show|hide)-deprecations  Show or hide deprecations details [default: show]\n\n  **** Ranges / Filters / Focus ****\n\n    You can run selected examples by specified the line numbers or ids\n\n      shellspec path/to/a_spec.sh:10   # Run the groups or examples that includes lines 10\n      shellspec path/to/a_spec.sh:@1-5 # Run the 5th groups/examples defined in the 1st group\n      shellspec a_spec.sh:10:@1:20:@2  # You can mixing multiple line numbers and ids with join by \":\"\n\n    -F, --focus                     Run focused groups / examples only\n    -P, --pattern PATTERN           Load files matching pattern [default: \"*_spec.sh\"]\n    -E, --example PATTERN           Run examples whose names include PATTERN\n    -T, --tag TAG[:VALUE]           Run examples with the specified TAG\n        --default-path PATH         Set the default path where looks for examples [default: \"spec\"]\n\n    You can specify the path recursively by prefixing it with the pattern \"*/\" or \"**/\"\n      (This is not glob patterns and requires quotes. It is also available with --default-path)\n\n      shellspec \"*/spec\"               # The pattern \"*/\" matches 1 directory\n      shellspec \"**/spec\"              # The pattern \"**/\" matches 0 and more directories\n      shellspec \"*/*/**/test_spec.sh\"  # These patterns can be specified multiple times\n\n    -L, --dereference               Dereference all symlinks in in the above pattern [default: disabled]\n\n  **** Coverage ****\n\n        --covdir DIRECTORY          Output directory of the Coverage Report [default: coverage]\n        --{no-}kcov                 Enable coverage using kcov [default: disabled]\n        --kcov-path PATH            Specify kcov path [default: kcov]\n        --kcov-options OPTIONS      Additional Kcov options (coverage limits, coveralls id, etc)\n\n  **** Utility ****\n\n        --init [TEMPLATE...]        Initialize your project with ShellSpec | [spec] [git] [hg] [svn]\n        --gen-bin [@COMMAND...]     Generate test support commands in \"\u003cHELPERDIR\u003e/support/bin\"\n        --count                     Count the number of specfiles and examples\n        --list LIST                 List the specfiles/examples | [specfiles] [examples(:id|:lineno)]\n        --syntax-check              Syntax check of the specfiles without running any examples\n        --translate                 Output translated specfile\n        --task [TASK]               Run the TASK or Show the task list if TASK is not specified\n        --docker DOCKER-IMAGE       Run tests in specified docker image (EXPERIMENTAL)\n    -v, --version                   Display the version\n    -h, --help                      -h: short help, --help: long help\n```\n\n## Project directory\n\nAll specfiles for ShellSpec must be under the project directory. The root of the project directory\nmust have a `.shellspec` file. This file is that specify the default options to be used in\nthe project, but an empty file is required even if the project has no options.\n\nNOTE: The `.shellspec` file was described in the documentation as a required file for some time,\nbut ShellSpec worked without it. Starting with version 0.28.0, this file is checked and will be\nrequired in future versions.\n\nYou can easily create the necessary files by executing the `shellspec --init` command in an existing directory.\n\n### Typical directory structure\n\nThis is the typical directory structure. Version 0.28.0 allows many of these to be changed by specifying options, supporting a more flexible [directory structure](docs/directory_structure.md).\n\n```text\n\u003cPROJECT-ROOT\u003e directory\n├─ .shellspec                       [mandatory]\n├─ .shellspec-local                 [optional] Ignore from version control\n├─ .shellspec-quick.log             [optional] Ignore from version control\n├─ report/                          [optional] Ignore from version control\n├─ coverage/                        [optional] Ignore from version control\n│\n├─ bin/\n│   ├─ your_script1.sh\n│              :\n├─ lib/\n│   ├─ your_library1.sh\n│              :\n│\n├─ spec/ (also \u003cHELPERDIR\u003e)\n│   ├─ spec_helper.sh               [recommended]\n│   ├─ banner[.md]                  [optional]\n│   ├─ support/                     [optional]\n│   │\n│   ├─ bin/\n│   │   ├─ your_script1_spec.sh\n│   │             :\n│   ├─ lib/\n│   │   ├─ your_library1_spec.sh\n```\n\n### Options file\n\nTo change the default options for the `shellspec` command, create options file(s).\nFiles are read in the order shown below, options defined last take precedence.\n\n1. `$XDG_CONFIG_HOME/shellspec/options`\n2. `$HOME/.shellspec-options` (version \u003e= 0.28.0) or `$HOME/.shellspec` (deprecated)\n3. `\u003cPROJECT-ROOT\u003e/.shellspec`\n4. `\u003cPROJECT-ROOT\u003e/.shellspec-local` (Do not store in VCS such as git)\n\nSpecify your default options with `$XDG_CONFIG_HOME/shellspec/options` or `$HOME/.shellspec-options`.\nSpecify default project options with `.shellspec` and overwrite to your favorites with `.shellspec-local`.\n\n### `.shellspec` - project options file\n\nSpecifies the default options to use for the project.\n\n### `.shellspec-local` - user custom options file\n\nOverride the default options used by the project with your favorites.\n\n### `.shellspec-basedir` - specfile execution base directory\n\nUsed to specify the directory in which the specfile will be run.\nSee [directory structure](docs/directory_structure.md) or `--execdir` option for details.\n\n### `.shellspec-quick.log` - quick execution log\n\nIf this file is present, Quick mode will be enabled and the log of Quick execution will be recorded.\nIt created automatically when `--quick` option is specified.\nIf you want to turn off Quick mode, delete it.\n\n### `report/` - report file directory\n\nThe output location for reports generated by the `--output` or `--profile` options.\nThis can be changed with the `--reportdir` option.\n\n### `coverage/` - coverage reports directory\n\nThe output location for coverage reports.\nThis can be changed with the `--covdir` option.\n\n### `spec/` - (default) specfiles directory\n\nBy default, it is assumed that all specfiles are store under the `spec` directory,\nbut it is possible to create multiple directories with different names.\n\nNOTE: In Version \u003c= 0.27.x, the `spec` directory was the only directory that contained the specfiles.\n\n### \\\u003cHELPERDIR\\\u003e (default: `spec/`)\n\nThe directory to store `spec_helper.sh` and other files.\nBy default, the `spec` directory also serves as `HELPERDIR` directory,\nbut you can change it to another directory with the `--helperdir` option.\n\n#### `spec_helper.sh` - (default) helper file for specfile\n\nThe `spec_helper.sh` is loaded to specfile by the `--require spec_helper` option.\nThis file is used to define global functions, initial setting for examples, custom matchers, etc.\n\n#### `banner[.md]` - banner file displayed at test execution\n\nIf the file `\u003cHELPERDIR\u003e/banner` or `\u003cHELPERDIR\u003e/banner.md` exists, Display a banner when\nthe `shellspec` command is executed. It can be used to display information about the tests.\nThe `--no-banner` option can be used to disable this behavior.\n\n#### `support/` - directory for support files\n\nThis directory can be used to store files such as custom matchers and tasks.\n\n##### `bin` - directory for support commands\n\nThis directory is used to store [support commands](#support-commands).\n\n## Specfile (test file)\n\nIn ShellSpec, you write your tests in a specfile.\nBy default, specfile is a file ending with `_spec.sh` under the `spec` directory.\n\nThe specfile is executed using the `shellspec` command, but it can also be executed directly.\nSee [self-executable specfile](#self-executable-specfile) for details.\n\n### Example\n\n```sh\nDescribe 'lib.sh' # example group\n  Describe 'bc command'\n    add() { echo \"$1 + $2\" | bc; }\n\n    It 'performs addition' # example\n      When call add 2 3 # evaluation\n      The output should eq 5  # expectation\n    End\n  End\nEnd\n```\n\n**The best place to learn how to write a specfile is the\n[examples/spec](examples/spec) directory. You should take a look at it!**\n*(Those examples include failure examples on purpose.)*\n\n### About DSL\n\nShellSpec has its own DSL to write tests. It may seem like a distinctive code because DSL starts\nwith a capital letter, but the syntax is compatible with shell scripts, and you can embed\nshell functions and use [ShellCheck](https://github.com/koalaman/shellcheck) to check the syntax.\n\nYou may feel rejected by this DSL, but It starts with a capital letter to avoid confusion with\nthe command, and it does a lot more than you think, such as realizing scopes, getting\nshell-independent line numbers, and workarounds for bugs in some shells.\n\n### Execution directory\n\nSince version 0.28.0, the working directory when running a specfile is the project root directory by default.\nEven if you run a specfile from a subdirectory in the project directory,\nit is the project root directory.\nBefore 0.27.x, it was the current directory when the `shellspec` command was executed.\n\nYou can change this directory (location) by using the `--execdir @LOCATION[/DIR]` option.\nYou can choose from the following locations and specify a path relative to the location if necessary.\nHowever, you cannot specify a directory outside the project directory.\n\n- `@project`   Where the `.shellspec` file is located (project root) [default]\n- `@basedir`   Where the `.shellspec` or `.shellspec-basedir` file is located\n- `@specfile`  Where the specfile is located\n\nIf `@basedir` is specified, the parent directory is searched from the directory containing the specfile\nto be run, and the first directory where `.shellspec-basedir` or `.shellspec` is found is used as\nthe execution directory. This is useful if you want to have a separate directory for each\nutility (command) you want to test.\n\nNOTE: You will need to change under the project directory or use the `-c` (`--chdir`) or\n`-C` (`--directory`) option before running the specfile.\n\n### Embedded shell scripts\n\nYou can embed shell functions (or shell script code) in the specfile.\nThis shell function can be used for test preparation and complex testing.\n\nNote that the specfile implements scope using subshells.\nShell functions defined in the specfile can only be used within blocks (e.g. `Describe`, `It`, etc).\n\nIf you want to use a global function, you can define it in `spec_helper.sh`.\n\n### Translation process\n\nThe specfile will not be executed directly by the shell, but will be translated into a regular\nshell script and output to a temporary directory (default: `/tmp`) before being executed.\n\nThe translation process is simple in that it only replaces forward-matched words (DSLs), with a few\nexceptions. If you are interested in the translated code, you can see with `shellspec --translate`.\n\n### Syntax formatter (`altshfmt`)\n\nThe specfile contains DSLs, so it cannot be properly formatted by general shell script formatters.\nIf you want to format the specfile, use [altshfmt](https://github.com/shellspec/altshfmt).\n\n## DSL syntax\n\n### Basic structure\n\n#### `Describe`, `Context`, `ExampleGroup` - example group block\n\n`ExampleGroup` is a block for grouping example groups or examples.\n`Describe` and `Context` are aliases for `ExampleGroup`.\nThey can be nested, and may contain example groups or examples.\n\n```sh\nDescribe 'is example group'\n  Describe 'is nestable'\n    ...\n  End\n\n  Context 'is used to facilitate understanding depending on the context'\n    ...\n  End\nEnd\n```\n\nThe example groups can be optionally tagged. See [Tagging](#tagging) for details.\n\n```sh\nDescribe 'is example group' tag1:value1 tag2:value2 ...\n```\n\n#### `It`, `Specify`, `Example` - example block\n\n`Example` is a block for writing an evaluation and expectations.\n`It` and `Specify` are aliases for `Example`.\n\nAn example is composed by up to one evaluation and multiple expectations.\n\n```sh\nadd() { echo \"$1 + $2\" | bc; }\n\nIt 'performs addition'          # example\n  When call add 2 3             # evaluation\n  The output should eq 5        # expectation\n  The status should be success  # another expectation\nEnd\n```\n\nThe examples can be optionally tagged. See [Tagging](#tagging) for details.\n\n```sh\nIt 'performs addition' tag1:value1 tag2:value2 ...\n```\n\n#### `Todo` - one liner empty example\n\n`Todo` is the same as the empty example and is treated as a [pending](#pending---pending-example) example.\n\n```sh\nTodo 'will be used later when we write a test'\n\nIt 'is an empty example, the same as Todo'\nEnd\n```\n\n#### `When` - evaluation\n\nEvaluation executes a shell function or command for verification.\nOnly one evaluation can be defined for each example and also can be omitted.\n\nSee more details of [Evaluation](docs/references.md#evaluation)\n\nNOTE: [About executing aliases](#about-executing-aliases)\n\n##### `call` - call a shell function (without subshell)\n\nIt calls a function without subshell.\nPractically, it can also run commands.\n\n```sh\nWhen call add 1 2 # call `add` shell function with two arguments.\n```\n\n##### `run` - run a command (within subshell)\n\nIt runs a command within subshell. Practically, it can also call a shell function.\nThe command does not have to be a shell script.\n\nNOTE: This does not support coverage measurement.\n\n```sh\nWhen run touch /tmp/foo # run `touch` command.\n```\n\nSome commands below are specially handled by ShellSpec.\n\n###### `command` - runs an external command\n\nIt runs a command, respecting shebang.\nIt can not call a shell function. The command does not have to be a shell script.\n\nNOTE: This does not support coverage measurement.\n\n```sh\nWhen run command touch /tmp/foo # run `touch` command.\n```\n\n###### `script` - runs a shell script\n\nIt runs a shell script, ignoring shebang. The script has to be a shell script.\nIt will be executed in another instance of the same shell as the current shell.\n\n```sh\nWhen run script my.sh # run `my.sh` script.\n```\n\n###### `source` - runs a script by `.` (dot) command\n\nIt sources a shell script, ignoring its shebang. The script has to be a shell script.\nIt is similar to `run script`, but with some differences.\nUnlike `run script`, function-based mocking is available.\n\n```sh\nWhen run source my.sh # source `my.sh` script.\n```\n\n##### About executing aliases\n\nIf you want to execute aliases, you need a workaround using `eval`.\n\n```sh\nalias alias-name='echo this is alias'\nWhen call alias-name # alias-name: not found\n\n# eval is required\nWhen call eval alias-name\n\n# When using embedded shell scripts\nfoo() { eval alias-name; }\nWhen call foo\n```\n\n#### `The` - expectation\n\nExpectation begins with `The` which does the verification.\nThe basic syntax is as follows:\n\n```sh\nThe output should equal 4\n```\n\nUse `should not` for the opposite verification.\n\n```sh\nThe output should not equal 4\n```\n\n##### Subjects\n\nThe subject is the target of the verification.\n\n```sh\nThe output should equal 4\n      |\n      +-- subject\n```\n\nThere are `output` (`stdout`), `error` (`stdout`), `status`, `variable`, `path`, etc. subjects.\n\nPlease refer to the [Subjects](docs/references.md#subjects) for more details.\n\n##### Modifiers\n\nThe modifier concretizes the target of the verification (subject).\n\n```sh\nThe line 2 of output should equal 4\n      |\n      +-- modifier\n```\n\nThe modifiers are chainable.\n\n```sh\nThe word 1 of line 2 of output should equal 4\n```\n\nIf the modifier argument is a number, you can use an ordinal numeral instead of a number.\n\n```sh\nThe first word of second line of output should equal 4\n```\n\nThere are `line`, `word`, `length`, `contents`, `result`, etc. modifiers.\nThe `result` modifier is useful for making the result of a user-defined function the subject.\n\nPlease refer to the [Modifiers](docs/references.md#modifiers) for more details.\n\n##### Matchers\n\nThe matcher is the verification.\n\n```sh\nThe output should equal 4\n                   |\n                   +-- matcher\n```\n\nThere are many matchers such as string matcher, status matcher, variable matchers and stat matchers.\nThe `satisfy` matcher is useful for verification with user-defined functions.\n\nPlease refer to the [Matchers](docs/references.md#matchers) for more details.\n\n##### Language chains\n\nShellSpec supports *language chains* like [chai.js](https://www.chaijs.com/).\nIt only improves readability, does not affect the expectation: `a`, `an`, `as`, `the`.\n\nThe following two sentences have the same meaning:\n\n```sh\nThe first word of second line of output should valid number\n\nThe first word of the second line of output should valid as a number\n```\n\n#### `Assert` - expectation for custom assertion\n\nThe `Assert` is yet another expectation to verify with a user-defined function.\nIt is designed for verification of side effects, not the result of the evaluation.\n\n```sh\nstill_alive() {\n  ping -c1 \"$1\" \u003e/dev/null\n}\n\nDescribe \"example.com\"\n  It \"responses\"\n    Assert still_alive \"example.com\"\n  End\nEnd\n```\n\n### Pending, skip and focus\n\n#### `Pending` - pending example\n\n`Pending` is similar to `Skip`, but the test passes if the verification fails,\nand the test fails if the verification succeeds. This is useful if you want to\nspecify that you will implement something later.\n\n```sh\nDescribe 'Pending'\n  Pending \"not implemented\"\n\n  hello() { :; }\n\n  It 'will success when test fails'\n    When call hello world\n    The output should \"Hello world\"\n  End\nEnd\n```\n\n#### `Skip` - skip example\n\nUse `Skip` to skip executing the example.\n\n```sh\nDescribe 'Skip'\n  Skip \"not exists bc\"\n\n  It 'is always skip'\n    ...\n  End\nEnd\n```\n\n##### `if` - conditional skip\n\nUse `Skip if` if you want to skip conditionally.\n\n```sh\nDescribe 'Conditional skip'\n  not_exists_bc() { ! type bc \u003e/dev/null 2\u003e\u00261; }\n  Skip if \"not exists bc\" not_exists_bc\n\n  add() { echo \"$1 + $2\" | bc; }\n\n  It 'performs addition'\n    When call add 2 3\n    The output should eq 5\n  End\nEnd\n```\n\n#### 'x' prefix for example group and example\n\n##### `xDescribe`, `xContext`, `xExampleGroup` - skipped example group\n\n`xDescribe`, `xContext`, `xExampleGroup` are skipped example group blocks.\nExecution of examples contained in these blocks is skipped.\n\n```sh\nDescribe 'is example group'\n  xDescribe 'is skipped example group'\n    ...\n  End\nEnd\n```\n\n##### `xIt`, `xSpecify`, `xExample` - skipped example\n\n`xIt`, `xSpecify`, `xExample` are skipped example blocks.\nExecution of the example is skipped.\n\n```sh\nxIt 'is skipped example'\n  ...\nEnd\n```\n\n#### 'f' prefix for example group and example\n\n##### `fDescribe`, `fContext`, `fExampleGroup` - focused example group\n\n`fDescribe`, `fContext`, `fExampleGroup` are focused example group blocks.\nOnly the examples included in these will be executed when the `--focus` option is specified.\n\n```sh\nDescribe 'is example group'\n  fDescribe 'is focus example group'\n    ...\n  End\nEnd\n```\n\n##### `fIt`, `fSpecify`, `fExample` - focused example\n\n`fIt`, `fSpecify`, `fExample` are focused example blocks.\nOnly these examples will be executed when the `--focus` option is specified.\n\n```sh\nfIt 'is focused example'\n  ...\nEnd\n```\n\n#### About temporary pending and skip\n\nUsing `Pending` or `Skip` without a message is a \"temporary pending\" or \"temporary skip\".\n\"x\"-prefixed example groups and examples are also treated as temporary skips.\n\nThe non-temporary `Pending` and `Skip` (with a message) are used when the case will take a long time to resolve.\nIt may be committed to a version control system. Temporary pending and skip are used during current work.\nWe do not recommend committing them to a version control system.\n\nThese two types differ in the display of the report. Refer to `--skip-message` and `--pending-message` options.\n\n```sh\n# Temporary pending and skip\nPending\nSkip\nSkip # this comment will be displayed in the report\nTodo\nxIt\n  ...\nEnd\n\n# Non-temporary pending and skip\nPending \"reason\"\nSkip \"reason\"\nSkip if \"reason\" condition\nTodo \"It will be implemented\"\n```\n\n### Hooks\n\n#### `BeforeEach` (`Before`), `AfterEach` (`After`) - example hook\n\nYou can specify commands to be executed before / after each example by `BeforeEach` (`Before`), `AfterEach` (`After`).\n\nNOTE: `BeforeEach` and `AfterEach` are supported in version 0.28.0 and later.\nPrevious versions should use `Before` and `After` instead.\n\nNOTE: `AfterEach` is for cleanup and not for assertions.\n\n```sh\nDescribe 'example hook'\n  setup() { :; }\n  cleanup() { :; }\n  BeforeEach 'setup'\n  AfterEach 'cleanup'\n\n  It 'is called before and after each example'\n    ...\n  End\n\n  It 'is called before and after each example'\n    ...\n  End\nEnd\n```\n\n#### `BeforeAll`, `AfterAll` - example group hook\n\nYou can specify commands to be executed before / after all examples by `BeforeAll` and `AfterAll`.\n\n```sh\nDescribe 'example all hook'\n  setup() { :; }\n  cleanup() { :; }\n  BeforeAll 'setup'\n  AfterAll 'cleanup'\n\n  It 'is called before/after all example'\n    ...\n  End\n\n  It 'is called before/after all example'\n    ...\n  End\nEnd\n```\n\n#### `BeforeCall`, `AfterCall` - call evaluation hook\n\nYou can specify commands to be executed before / after call evaluation by `BeforeCall` and `AfterCall`.\n\nNOTE: These hooks were originally created to test ShellSpec itself.\nPlease use the `BeforeEach` / `AfterEach` hooks whenever possible.\n\n```sh\nDescribe 'call evaluation hook'\n  setup() { :; }\n  cleanup() { :; }\n  BeforeCall 'setup'\n  AfterCall 'cleanup'\n\n  It 'is called before/after call evaluation'\n    When call hello world\n    ...\n  End\nEnd\n```\n\n#### `BeforeRun`, `AfterRun` - run evaluation hook\n\nYou can specify commands to be executed before / after run evaluation\n(`run`, `run command`, `run script`, and `run source`) by `BeforeRun` and `AfterRun`.\n\nThese hooks are executed in the same subshell as the \"run evaluation\".\nTherefore, you can access the variables after executing the evaluation.\n\nNOTE: These hooks were originally created to test ShellSpec itself.\nPlease use the `BeforeEach` / `AfterEach` hooks whenever possible.\n\n```sh\nDescribe 'run evaluation hook'\n  setup() { :; }\n  cleanup() { :; }\n  BeforeRun 'setup'\n  AfterRun 'cleanup'\n\n  It 'is called before/after run evaluation'\n    When run hello world\n    ...\n  End\nEnd\n```\n\n#### Pitfalls\n\nThe hooks may fail in subtle ways if there is output to stderr, even if the\nreturn code / exit code is `0`.\n\nCommands like `git checkout` routinely write to stderr, even if there was no actual\nfailure, so be aware that your hooks may fail because of this.\n\n### Helpers\n\n#### `Dump` - dump stdout, stderr, and status for debugging\n\nDump stdout, stderr, and status of the evaluation. It is useful for debugging.\n\n```sh\nWhen call echo hello world\nDump # stdout, stderr and status\n```\n\n#### `Include` - include a script file\n\nInclude a shell script to test.\n\n```sh\nDescribe 'lib.sh'\n  Include lib.sh # hello function defined\n\n  Describe 'hello()'\n    It 'says hello'\n      When call hello ShellSpec\n      The output should equal 'Hello ShellSpec!'\n    End\n  End\nEnd\n```\n\n#### `Set` - set shell options\n\nSet shell options before executing each example.\nThe shell option name is the long name of `set` or the name of `shopt`:\n\nNOTE: Use `Set` instead of the `set` command because the `set` command\nmay not work as expected in some shells.\n\n```sh\nDescribe 'Set helper'\n  Set 'errexit:off' 'noglob:on'\n\n  It 'sets shell options before executing the example'\n    When call foo\n  End\nEnd\n```\n\n#### `Path`, `File`, `Dir` - path alias\n\n`Path` is used to define a short pathname alias.\n`File` and `Dir` are aliases for `Path`.\n\n```sh\nDescribe 'Path helper'\n  Path hosts-file=\"/etc/hosts\"\n\n  It 'defines short alias for long path'\n    The path hosts-file should exist\n  End\nEnd\n```\n\n#### `Data` - pass data as stdin to evaluation\n\nYou can use the Data Helper which inputs data from stdin for evaluation.\nThe input data is specified after `#|` in the `Data` or `Data:expand` block.\n\n```sh\nDescribe 'Data helper'\n  It 'provides with Data helper block style'\n    Data # Use Data:expand instead if you want expand variables.\n      #|item1 123\n      #|item2 456\n      #|item3 789\n    End\n    When call awk '{total+=$2} END{print total}'\n    The output should eq 1368\n  End\nEnd\n```\n\nYou can also use a file, function or string as data sources.\n\nSee more details of [Data](docs/references.md#data)\n\n#### `Parameters` - parameterized example\n\nParameterized tests (aka [Data-driven testing](https://en.wikipedia.org/wiki/Data-driven_testing))\nare used to run the same test once for each set of parameters.\n`Parameters` defines a block of parameters.\n\n```sh\nDescribe 'example'\n  Parameters\n    \"#1\" 1 2 3\n    \"#2\" 1 2 3\n  End\n\n  Example \"example $1\"\n    When call echo \"$(($2 + $3))\"\n    The output should eq \"$4\"\n  End\nEnd\n```\n\nIn addition to the default `Parameters` block, three additional styles are supported:\n`Parameters:value`, `Parameters:matrix` and `Parameters:dynamic`.\n\nSee more details of [Parameters](docs/references.md#parameters)\n\nNOTE: You can also combine the `Parameters` and `Data:expand` helpers.\n\n#### `Mock` - create a command-based mock\n\nSee [Command-based mock](#command-based-mock)\n\n#### `Intercept` - create an intercept point\n\nSee [Intercept](#intercept)\n\n## Directives\n\nDirectives are instructions that can be used in embedded shell scripts.\nIt is used to solve small problems of shell scripts in testing.\n\nThis is like a shell function, but not a shell function.\nTherefore, the supported grammar is limited and can only be used at the\nbeginning of a function definition or at the beginning of a line.\n\n```sh\nfoo() { %puts \"foo\"; } # supported\n\nbar() {\n  %puts \"bar\" # supported\n}\n\nbaz() {\n  any command; %puts \"baz\" # not supported\n}\n```\n\n### `%const` (`%`) - constant definition\n\n`%const` (`%` is short hand) directive defines a constant value. The characters\nwhich can be used for variable names are uppercase letters `[A-Z]`, digits\n`[0-9]` and underscore `_` only. It can not be defined inside an example\ngroup nor an example.\n\nThe value is evaluated during the specfile translation process.\nSo you can access ShellSpec variables, but you can not access variable or\nfunction in the specfile.\n\nThis feature assumes use with conditional skip. The conditional skip may run\noutside of the examples. As a result, sometimes you may need variables defined\noutside of the examples.\n\n### `%text` - embedded text\n\nYou can use the `%text` directive instead of a hard-to-use heredoc with\nindented code. The input data is specified after `#|`.\n\n```sh\nDescribe '%text directive'\n  It 'outputs texts'\n    output() {\n      echo \"start\" # you can write code here\n      %text\n      #|aaa\n      #|bbb\n      #|ccc\n      echo \"end\" # you can write code here\n    }\n\n    result() { %text\n      #|start\n      #|aaa\n      #|bbb\n      #|ccc\n      #|end\n    }\n\n    When call output\n    The output should eq \"$(result)\"\n    The line 3 of output should eq 'bbb'\n  End\nEnd\n```\n\n### `%puts` (`%-`), `%putsn` (`%=`) - output a string (with newline)\n\n`%puts` (put string) and `%putsn` (put string with newline) can be used instead\nof (not portable) echo. Unlike echo, it does not interpret escape sequences\nregardless of the shell. `%-` is an alias of `%puts`, `%=` is an alias of\n`%putsn`.\n\n### `%printf` - alias for printf\n\nThis is the same as `printf`, but it can be used in the sandbox mode because the path has been resolved.\n\n### `%sleep` - alias for sleep\n\nThis is the same as `sleep`, but it can be used in the sandbox mode because the path has been resolved.\n\n### `%preserve` - preserve variables\n\nUse the `%preserve` directive to preserve the variables in subshells and external shell scripts.\n\nIn the following cases, `%preserve` is required because variables are not preserved.\n\n- `When run` evaluation - It runs in a subshell.\n- Command-based mock (`Mock`) - It is an external shell script.\n- Function-based Mock called by command substitution\n\n```sh\nDescribe '%preserve directive'\n  It 'preserves variables'\n    func() { foo=1; bar=2; baz=3; }\n    preserve() { %preserve bar baz:BAZ; }\n    AfterRun preserve\n\n    When run func\n    The variable foo should eq 1 # This will be failure\n    The variable bar should eq 2 # This will be success\n    The variable BAZ should eq 3 # Preserved to different variable (baz:BAZ)\n  End\nEnd\n```\n\n### `%logger` - debug output\n\nOutput log messages to the log file (default: `/dev/tty`) for debugging.\n\n### `%data` - define parameter\n\nSee [Parameters:dynamic](docs/references.md#parametersdynamic).\n\n## Mocking\n\nThere are two ways to create a mock, (shell) function-based mock and (external) command-based mock.\nThe function-based mock is usually recommended for performance reasons.\nBoth can be overwritten with an internal block and will be restored when the block ends.\n\n### Function-based mock\n\nThe (shell) function-based mock is simply (re)defined with a shell function.\n\n```sh\nDescribe 'function-based mock'\n  get_next_day() { echo $(($(date +%s) + 86400)); }\n\n  date() {\n    echo 1546268400\n  }\n\n  It 'calls the date function'\n    When call get_next_day\n    The stdout should eq 1546354800\n  End\nEnd\n```\n\n### Command-based mock\n\nThe (external) command-based mock creates a temporary mock shell script and runs as an external command.\nThis is slow, but there are some advantages over the function-based mock.\n\n- Can be use invalid characters as the shell function name.\n  - e.g. `docker-compose` (`-` cannot be used as a function name in POSIX)\n- Can be invoke a mocked command from an external command (not limited to shell script).\n\nA command-based mock creates an external shell script with the contents of a `Mock` block,\nso there are some restrictions.\n\n- It is not possible to mock shell functions or shell built-in functions.\n- It is not possible to call shell functions outside the `Mock` block.\n  - Exception: Can be called exported (`export -f`) functions. (bash only)\n- To reference variables outside the `Mock` block, they must be exported.\n- To return a variable from a Mock block, you need to use the `%preserve` directive.\n\n```sh\nDescribe 'command-based mock'\n  get_next_day() { echo $(($(date +%s) + 86400)); }\n\n  Mock date\n    echo 1546268400\n  End\n\n  It 'runs the mocked date command'\n    When call get_next_day\n    The stdout should eq 1546354800\n  End\nEnd\n```\n\nNOTE: To achieve this feature, a directory for mock commands is included at the beginning of the `PATH`.\n\n## Support commands\n\n### Execute the actual command within a mock function\n\nSupport commands are helper commands that can be used in the specfile.\nFor example, it can be used in a mock function to execute the actual command.\nIt is recommended that the support command name be the actual command name prefixed with `@`.\n\n```sh\nDescribe \"Support commands example\"\n  touch() {\n    @touch \"$@\" # @touch executes actual touch command\n    echo \"$1 was touched\"\n  }\n\n  It \"touch a file\"\n    When run touch \"file\"\n    The output should eq \"file was touched\"\n    The file \"file\" should exist\n  End\nEnd\n```\n\nSupport commands are generated in the `spec/support/bin` directory by the `--gen-bin` option.\nFor example run `shellspec --gen-bin @touch` to generate the `@touch` command.\n\nThis is the main purpose, but support commands are just shell scripts, so they can\nalso be used for other purposes. You can freely edit the support command script.\n\n### Make mock not mandatory in sandbox mode\n\nThe sandbox mode forces the use of mocks. However, you may not want to require mocks for some commands.\nFor example, `printf` is a built-in command in many shells and does not require a mock in the sandbox mode for these shells. But\nthere are shells where it is an external command and then it requires to be mocked.\n\nTo allow `printf` to be called without mocking in certain cases,\ncreate a support command named `printf` (`shellspec --gen-bin printf`).\n\n### Resolve command incompatibilities\n\nSome commands have different options between BSD and GNU.\nIf you handle the difference in the specfile, the test will be hard to read.\nYou can solve it with the support command.\n\n```sh\n#!/bin/sh -e\n# Command name: @sed\n. \"$SHELLSPEC_SUPPORT_BIN\"\ncase $OSTYPE in\n  *darwin*) invoke gsed \"$@\" ;;\n  *) invoke sed \"$@\" ;;\nesac\n```\n\n## Tagging\n\nThe example groups or examples can be tagged, and the `--tag` option can be used to filter the examples to be run.\nThe tag name and tag value are separated by `:`, and the tag value is optional. You can use any character if quoted.\n\n```sh\nDescribe \"Checking something\" someTag:someVal\n  It \"does foo\" tagA:val1\n    ...\n  It \"does bar\" tagA:val2\n    ...\n  It \"does baz\" tagA\n    ...\nEnd\n```\n\n1. Everything nested inside a selected element is selected in parent elements. e.g. `--tag someTag` will select everything above.\n2. Specifying a tag but no value selects everything with that tag whether or not it has a value, e.g. `--tag tagA` will select everything above.\n3. Specifying multiple tags will select the union of everything tagged, e.g. `--tag tagA:val1,tagA:val2` will select `does foo` and `does bar`.\n4. Tests included multiple times are not a problem, e.g. `--tag someTag,tagA,tagA:val1` just selects everything.\n5. If no tag matches, nothing will be run, e.g. `--tag tagA:` runs nothing (it does not match baz above, as empty values are not the same as no value).\n6. The --tag option can be used multiple times, e.g. `--tag tagA:val1 --tag tagA:val2` works the same as `--tag tagA:val1,tagA:val2`\n\n## About testing external commands\n\nShellSpec is a testing framework for shell scripts, but it can be used to test anything that can be executed as an external command, even if it is written in another language. Even shell scripts can be tested as external commands.\n\nIf you are testing a shell script as an external command, please note the following.\n\n- It will be executed in the shell specified by the shebang not the shell running the specfile.\n- The coverage of the shell script will not be measured.\n- Cannot refer to variables inside the shell script.\n- Shell built-in commands cannot be mocked.\n- Functions defined inside the shell script cannot be mocked.\n- Only command-based mock can be used (if the script is calling an external command).\n- Interceptor is not available.\n\nTo get around these limitations, use `run script` or `run source`. See [How to test a single file shell script](#how-to-test-a-single-file-shell-script).\n\n## How to test a single file shell script\n\nIf the shell script consists of a single file, unit testing becomes difficult.\nHowever, there are many such shell scripts.\n\nShellSpec has the ability to testing in such cases with only few modifications to the shell script.\n\n### Using `run script`\n\nUnlike the case of executing as an [external command](#about-testing-external-commands), it has the following features.\n\n- It will run in the same shell (but another process) that is running specfile.\n- The coverage of the shell script will be measured.\n\nThere are limitations as follows.\n\n- Cannot refer to variables inside the shell script.\n- Shell built-in commands cannot be mocked.\n- Functions defined inside the shell script cannot be mocked.\n- Only command-based mock can be used (if the script is calling an external command).\n- Interceptor is not available.\n\n### Using `run source`\n\nIt is even less limitations than `run script` and has the following features.\n\n- It will run in the same shell and same process that is running specfile.\n- The coverage of the shell script will be measured.\n- Can be refer to variables inside the shell script.\n- Function-based mock and command-based mock are available.\n- Interceptor is available.\n- Shell built-in commands can be mocked.\n- Functions defined inside the shell script can be mocked using interceptor.\n\nHowever, since it is simulated using the `.` command, there are some differences in behavior.\nFor example, the value of `$0` is different.\n\nNOTE: Mocking of shell built-in commands can be done before `run source`. However, if you are using\ninterceptor, mocking of the `test` command must be done in the `__\u003cname\u003e__` function.\n\n### Testing shell functions\n\n#### `__SOURCED__`\n\nThis is the way to test shell functions defined in a shell script.\n\nLoading a script with `Include` defines a `__SOURCED__` variable available in the sourced script.\nIf the variable `__SOURCED__` is defined, please return from the shell script.\n\n```sh\n#!/bin/sh\n# hello.sh\n\nhello() { echo \"Hello $1\"; }\n\n# This is the writing style presented by ShellSpec, which is short but unfamiliar.\n# Note that it returns the current exit status (could be non-zero).\n${__SOURCED__:+return}\n\n# The above means the same as below.\n# ${__SOURCED__:+x} \u0026\u0026 return $?\n\n# If you don't like the coding style, you can use the general writing style.\n# if [ \"${__SOURCED__:+x}\" ]; then\n#   return 0\n# fi\n\nhello \"$1\"\n```\n\n```sh\nDescribe \"hello.sh\"\n  Include \"./hello.sh\"\n\n  Describe \"hello()\"\n    It \"says hello\"\n      When call hello world\n      The output should eq \"Hello world\"\n    End\n  End\nEnd\n```\n\n### Intercepting\n\nInterceptor is a feature that allows you to intercept your shell script in the middle of its execution.\nThis makes it possible to mock functions that cannot be mocked in advance at arbitrary timing,\nand to make assertions by retrieving the state of during script execution.\n\nIt is a powerful feature, but avoid using it as possible, because it requires you to modify your code\nand may reduce readability. Normally, it is not a good idea to modify the code just for testing,\nbut in some cases, there is no choice but to use this.\n\n```sh\n#!/bin/sh\n# ./today.sh\n\n# When run directly without testing, the \"__()\" function does nothing.\ntest || __() { :; }\n\n# the \"now()\" function is defined here, so it can't be mocked in advance.\nnow() { date +\"%Y-%m-%d %H:%M:%S\"; }\n\n# The function you want to test\ntoday() {\n  now=$(now)\n  echo \"${now% *}\"\n}\n\n# I want to mock the \"now()\" function here.\n__ begin __\n\ntoday=$(today)\necho \"Today is $today\"\n\n__ end __\n```\n\n```sh\nDescribe \"today.sh\"\n  Intercept begin\n  __begin__() {\n    now() { echo \"2021-01-01 01:02:03\"; }\n  }\n  __end__() {\n    # The \"run source\" is run in a subshell, so you need to use \"%preserve\"\n    # to preserve variables\n    %preserve today\n  }\n\n  It \"gets today's date\"\n    When run source ./today.sh\n    The output should eq \"Today is 2021-01-01\"\n    The variable today should eq \"2021-01-01\"\n  End\nEnd\n```\n\n#### `Intercept`\n\nUsage: `Intercept [\u003cname\u003e...]`\n\nSpecify the name(s) to intercept.\n\nNOTE: I will change `Intercept` to `Interceptors` to make it a declarative DSL.\n\n#### `test || __() { :; }`\n\nDefine the `__` function that does nothing except when run as a test (via ShellSpec).\nThis allows you to run it as a production without changing the code.\n\nThe `test` command is the shell built-in `test` command. This command returns false (non-zero)\nwhen called with no arguments. This will allow who are not familiar with ShellSpec to will\nunderstand what the result will be, even if they don't know what the code is for.\nOf course, it is good practice to comment on what the code is for\n\nWhen run via ShellSpec, the `test` command is redefined and returns true \"only once\" when called\nwith no arguments. After that, it will return to its original behavior. This means that this code\nneeds to be executed only once, at the start of the shell script.\n\n#### `__`\n\nUsage: `__ \u003cname\u003e [arguments...] __`\n\nThis is where the process is intercepted. You can define more than one.\nIf the name matches the name specified in `Intercept`, the `__\u003cname\u003e__` function will be called.\n\nNote that if the name is not specified in `Intercept`, nothing will be done,\nbut the exit status will be changed to 0.\n\n## spec_helper\n\nThe `spec_helper` can be used to set shell options for all specfiles,\ndefine global functions,check the execution shell, load custom matchers, etc.\n\nThe `spec_helper` is the default module name. It can be changed to any other name, and multiple\nmodules can be used. Only characters accepted by POSIX as identifiers can be used in module names.\nThe file name of the module must be the module name with the extension `.sh` appended.\nIt is loaded from `SHELLSPEC_LOAD_PATH` using the `--require` option.\n\nThe following is a typical `spec_helper`. The following three callback functions are available.\n\n```sh\n# Filename: spec/spec_helper.sh\n\nset -eu\n\nspec_helper_precheck() {\n  minimum_version \"0.28.0\"\n  if [ \"$SHELL_TYPE\" != \"bash\" ]; then\n    abort \"Only bash is supported.\"\n  fi\n}\n\nspec_helper_loaded() {\n  : # In most cases, you won't use it.\n}\n\nspec_helper_configure() {\n  import 'support/custom_matcher'\n  before_each \"global_before_each_hook\"\n}\n\n# User-defined global function\nglobal_before_each_hook() {\n  :\n}\n\n# In version \u003c= 0.27.x, only shellspec_spec_helper_configure was available.\n# This callback function is still supported but deprecated in the future.\n# Please rename it to spec_helper_configure.\n# shellspec_spec_helper_configure() {\n#  :\n# }\n```\n\nThe `spec_helper` will be loaded at least twice. The first time is at precheck phase,\nwhich is executed in a separate process before the specfile execution.\nThe second time will be load at the beginning of the specfile execution.\nIf you are using parallel execution, it will be loaded every specfile.\n\nWithin each callback function, there are several helper functions available. These functions are\nnot available outside of the callback function. Also, these callback functions will be removed\nautomatically when `spec_helper` is finished loading. (User-defined functions will not be removed.)\n\n### `\u003cmodule\u003e_precheck`\n\nThis callback function will be invoked only once before loading specfiles.\nExit with `exit` or `abort`, or `return` non-zero to exit without executing specfiles.\nInside this function, `set -eu` is executed, so an explicit return on error is not necessary.\n\nSince it is invoked in a separate process from specfiles, changes made in\nthis function will not be affected in specfiles.\n\n#### `minimum_version`\n\n- Usage: `minimum_version \u003cversion\u003e`\n\nSpecifies the minimum version of ShellSpec that the specfile supports. The version format is\n[semantic version](https://semver.org/). Pre-release versions have a lower precedence than\nthe associated normal version, but comparison between pre-release versions is not supported.\nThe build metadata will simply be ignored.\n\nNOTE: Since `\u003cmodule\u003e_precheck` is only available in 0.28.0 or later,\nit can be executed with earlier ShellSpecs even if minimum_version is specified.\nTo avoid this, you can implement a workaround using `--env-from`.\n\n```sh\n# spec/env.sh\n# Add `--env-from spec/env.sh` to `.shellspec`\nmajor_minor=${SHELLSPEC_VERSION%\".${SHELLSPEC_VERSION#*.*.}\"}\nif [ \"${major_minor%.*}\" -eq 0 ] \u0026\u0026 [ \"${major_minor#*.}\" -lt 28 ]; then\n  echo \"ShellSpec version 0.28.0 or higher is required.\" \u003e\u00262\n  exit 1\nfi\n```\n\n#### `error`, `warn`, `info`\n\n- Usage: `error [messages...]`\n- Usage: `warn [messages...]`\n- Usage: `info [messages...]`\n\nOutputs a message according to the type. You can also use `echo` or `printf`.\n\n#### `abort`\n\n- Usage: `abort [messages...]`\n- Usage: `abort \u003cexit status\u003e [messages...]`\n\nDisplay an error message and `exit`. If the exit status is omitted, it is `1`.\nYou can also exit with exit. `exit 0` will exit normally without executing the specfiles.\n\n#### `setenv`, `unsetenv`\n\n- Usage: `setenv [name=value...]`\n- Usage: `unset [name...]`\n\nYou can use `setenv` or `unsetenv` to pass or remove environment variables from precheck to specfiles.\n\n#### environment variables\n\nThe following environment variables are defined.\n\n- `VERSION` - ShellSpec Version\n- `SHELL_TYPE` - Currently running shell type (e.g. `bash`)\n- `SHELL_VERSION` - Currently running shell version (e.g. `4.4.20(1)-release`)\n\nNOTE: Be careful not to confuse `SHELL_TYPE` with the environment variable `SHELL`.\nThe environment variable `SHELL` is the user login shell, not the currently running shell.\nIt is a variable set by the system, and which unrelated to ShellSpec.\n\n### `\u003cmodule\u003e_loaded`\n\nIt is called after loading the shellspec's general internal functions,\nbut before loading the core modules (subject, modifier, matcher, etc).\nIf parallel execution is enabled, it may be called multiple times in isolated processes.\nInternal functions starting with `shellspec_` can also be used, but be aware that they may change.\n\nThis was created to perform [workarounds](helper/ksh_workaround.sh) for specific shells in order to\ntest ShellSpec itself. Other than that, I have not come up with a case where this is\nabsolutely necessary, but if you have one, please let me know.\n\n### `\u003cmodule\u003e_configure`\n\nThis callback function will be called after core modules (subject, modifier, matcher, etc) has been loaded.\nIf parallel execution is enabled, it may be called multiple times in isolated processes.\nInternal functions starting with `shellspec_` can also be used, but be aware that they may change.\nIt can be used to set global hooks, load custom matchers, etc., and override core module functions.\n\n#### `import`\n\n- Usage: `import \u003cmodule\u003e [arguments...]`\n\nImport a custom module from `SHELLSPEC_LOAD_PATH`.\n\n#### `before_each`, `after_each`\n\n- Usage: `before_each [hooks...]`\n- Usage: `after_each [hooks...]`\n\nRegister hooks to be executed before and after every example.\nIt is the same as executing `BeforeEach`/`AfterEach` at the top of all specfiles.\n\n#### `before_all`, `after_all`\n\n- Usage: `before_all [hooks...]`\n- Usage: `after_all [hooks...]`\n\nRegister hooks to be executed before and after all example.\nIt is the same as executing `BeforeAll`/`AfterAll` at the top of all specfiles.\n\nNOTE: This is a hook that is called before and after each specfile, not before and after all specfiles.\n\n## Self-executable specfile\n\nAdd `eval \"$(shellspec - -c) exit 1\"` to the top of the specfile and give execute permission\nto the specfile. You can use `/bin/sh`, `/usr/bin/env bash`, etc. for shebang.\nThe specfile will be run in the shell written in shebang.\n\n```sh\n#!/bin/sh\n\neval \"$(shellspec - -c) exit 1\"\n\n# Use the following if version \u003c= 0.27.x\n# eval \"$(shellspec -)\"\n\nDescribe \"bc command\"\n  bc() { echo \"$@\" | command bc; }\n\n  It \"performs addition\"\n    When call bc \"2+3\"\n    The output should eq 5\n  End\nEnd\n```\n\nThe `-c` option is available since 0.28.0, and you can also pass other options.\nIf you run the specfile directly, `--pattern` will be automatically set to `*`.\nThese options will be ignored if run via `shellspec` command.\n\nThe use of `shellspec` as shebang is deprecated because it is not portable.\n\n```awk\n#!/usr/bin/env shellspec -c\nLinux does not allow passing options\n\n#!/usr/bin/env -S shellspec -c\nThe -S option requires GNU Core Utilities 8.30 (2018-07-01) or later.\n```\n\n## Use with Docker\n\nYou can run ShellSpec without installation using Docker. ShellSpec and\nspecfiles run in a Docker container.\n\nSee [How to use ShellSpec with Docker](docs/docker.md).\n\n## Extension\n\n### Custom subject, modifier and matcher\n\nYou can create custom subject, custom modifier and custom matcher.\n\nSee [examples/spec/support/custom_matcher.sh](examples/spec/support/custom_matcher.sh) for custom matcher.\n\nNOTE: If you want to verify using shell function, you can use [result](docs/references.md#result) modifier or\n[satisfy](docs/references.md#satisfy) matcher. You don't need to create a custom matcher, etc.\n\n## Code Coverage\n\nShellSpec has integrated coverage feature. To use this feature [Kcov][] (v38 or later) is required.\n\n[Kcov]: https://github.com/SimonKagstrom/kcov\n\n### Supported shells\n\nSupported only in **bash**, **zsh**, and **ksh**, where `DEBUG` trap is implemented.\nHowever, we recommend latest **bash** for the following reasons.\n\n- bash (older versions): There seems to be some code that cannot be measured correctly.\n- zsh: There seems to be some code that cannot be measured correctly, and the measurement rate will be the lowest.\n- ksh: ksh93u+ and ksh2020 may have side effects on exit status when DEBUG trap is enabled due to a bug.\nThis bug has been [fixed](https://github.com/ksh93/ksh/issues/155) in [ksh93u+m](https://github.com/ksh93/ksh).\nThese are also prone to instability, especially with ksh2020 (which has been abandoned).\n\nIn any shell, some code may not be measured correctly (e.g., code containing `eval` or newline).\nThese are limitations and problems caused by shells and Kcov.\n\n### Measurement target\n\nShellSpec measures only the necessary codes to improve the measurement speed.\nAlso, there are some things that cannot be measured due to implementation.\n\n- The shell scripts loaded by `Include` will be measured.\n- The shell functions called by the `When` evaluation will be measured.\n- The shell scripts executed by the `When run script` evaluation will be measured.\n- The shell scripts executed by the `When run source` evaluation will be measured.\n- The external commands executed by the `When` evaluation will NOT be measured.\n  - Even if it is a shell script, it is not measured when it is executed as an external command.\n- If other than the above, it will not be measured.\n\nBy default only shell scripts whose names contain `.sh` are coverage targeted.\nIf you want to include other files, you need to adjust options with `--kcov-options`.\n\n```sh\n# Default kcov (coverage) options\n--kcov-options \"--include-path=. --path-strip-level=1\"\n--kcov-options \"--include-pattern=.sh\"\n--kcov-options \"--exclude-pattern=/.shellspec,/spec/,/coverage/,/report/\"\n\n# Example: Include script \"myprog\" with no extension\n--kcov-options \"--include-pattern=.sh,myprog\"\n\n# Example: Only specified files/directories\n--kcov-options \"--include-pattern=myprog,/lib/\"\n```\n\n### Coverage report\n\n[Coverage report][coverage] and `cobertura.xml` and `sonarqube.xml` files are generated under the coverage directory by Kcov.\nYou can easily integrate with [Coveralls](https://coveralls.io/), [Code Climate](https://codeclimate.com/),\n[Codecov](https://codecov.io/), etc.\n\n## For developers\n\n### Subprojects\n\n#### ShellMetrics - Cyclomatic Complexity Analyzer for shell scripts\n\nURL: [https://github.com/shellspec/shellmetrics](https://github.com/shellspec/shellmetrics)\n\n#### ShellBench - A benchmark utility for POSIX shell comparison\n\nURL: [https://github.com/shellspec/shellbench](https://github.com/shellspec/shellbench)\n\n#### altshfmt - AltSH (alternative shell script) formatter\n\nURL: [https://github.com/shellspec/altshfmt](https://github.com/shellspec/altshfmt)\n\n### Related projects\n\n#### getoptions - An elegant option parser and generator for shell scripts\n\nURL: [https://github.com/ko1nksm/getoptions](https://github.com/ko1nksm/getoptions)\n\n#### readlinkf - readlink -f implementation for shell scripts\n\nURL: [https://github.com/ko1nksm/readlinkf](https://github.com/ko1nksm/readlinkf)\n\n#### portable-echo - Portable echo shell function for POSIX compliant shells\n\nURL: [https://github.com/ko1nksm/portable-echo.sh](https://github.com/ko1nksm/portable-echo.sh)\n\n### Inspired frameworks\n\n- [RSpec](https://rspec.info/) - Behaviour Driven Development for Ruby\n- [Jest](https://jestjs.io/]) - Delightful JavaScript Testing\n- [Mocha](https://mochajs.org/) - the fun, simple, flexible JavaScript test framework\n- [Jasmine](https://jasmine.github.io/) - Behavior-Driven JavaScript\n- [Ginkgo](https://onsi.github.io/ginkgo/) - A Golang BDD Testing Framework\n- [JUnit 5](https://junit.org/junit5/) - The programmer-friendly testing framework for Java\n\n### Contributions\n\nAll contributions are welcome!\n\nShellSpec uses a peculiar coding style to assure high performance,\nreliability and portability, and the external commands allowed to use are greatly restricted.\n\nWe recommend that you create WIP PR early or offer suggestions in discussions to avoid ruining your work.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md)\n\n---\n\nAuthor: Koichi Nakashima ([ko1nksm](https://github.com/ko1nksm))\n","funding_links":["https://github.com/sponsors/ko1nksm"],"categories":["Other Resources","Shell","bash","Development","Shell Script Development","Producers"],"sub_categories":["ZSH Tools","Testing","Directory Navigation","Bash"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshellspec%2Fshellspec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshellspec%2Fshellspec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshellspec%2Fshellspec/lists"}