Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,11 @@ jobs:
- name: Install greadlink
if: startsWith(runner.os, 'macOS')
run: brew install coreutils
- name: Install parallel
if: startsWith(runner.os, 'macOS')
run: |
brew install parallel
which parallel # Verify installation
- name: Test code
run: test/run
env:
# Ubuntu runners ship GNU parallel, causing --tap + --jobs count mismatches.
# Force single-threaded on Linux; let macOS use parallel (installed above).
TEST_JOBS: ${{ runner.os == 'Linux' && '1' || 'detect' }}
# --tap + --jobs causes TAP plan count mismatches on both Linux and macOS.
TEST_JOBS: 1

build-docs:
runs-on: ubuntu-latest
Expand Down
13 changes: 13 additions & 0 deletions completion/available/herdr.completion.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# shellcheck shell=bash
about-completion "Herdr Terminal Multiplexer tab completion"

if ! _binary_exists herdr; then
_log_error "herdr not found in PATH — completion not loaded. (${BASH_SOURCE[0]})"
return 1
else
if ! _bash-it-completion-helper-sufficient herdr; then
_log_warning "The completion is set for 'herdr' externally. Activation will be skipped. (${BASH_SOURCE[0]})"
else
eval "$(herdr completion bash)"
fi
fi
13 changes: 13 additions & 0 deletions completion/available/op.completion.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# shellcheck shell=bash
about-completion "1Password CLI tab completion"

if ! _binary_exists op; then
_log_error "op not found in PATH — completion not loaded. (${BASH_SOURCE[0]})"
return 1
else
if ! _bash-it-completion-helper-sufficient op; then
_log_warning "The completion is set for 'op' externally. Activation will be skipped. (${BASH_SOURCE[0]})"
else
eval "$(op completion bash)"
fi
fi
41 changes: 35 additions & 6 deletions docs/test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,46 @@ To execute the unit tests, please run the ``run`` script:

The ``run`` script will automatically install if it is not already present, and will then run all tests found under the ``test`` directory, including subdirectories.

To run only a subset of the tests, you can provide the name of the test subdirectory that you want to run, e.g. like this for the tests in the ``test/themes`` directory:
To run only a subset of the tests, you can provide a directory or a specific test file:

.. code-block:: bash

# If you are in the root `.bash_it` directory:
# Run all tests in a directory:
test/run test/themes

By default, the tests run in single-threaded mode.
If you want to speed up the test execution, you can install the `GNU ``parallel`` tool <https://www.gnu.org/software/parallel/>`_\ , which is supported by Bats.
When using ``parallel``\ , the ``test/run`` script will use a number of threads in parallel, depending on the available CPU cores of your system.
This can speed up test execution significantly.
# Run a single test file:
test/run test/completion/op.completion.bats

# Run multiple specific files:
test/run test/completion/op.completion.bats test/completion/herdr.completion.bats

The tests always run in single-threaded mode (``TEST_JOBS=1``). Parallel execution
via GNU ``parallel`` was previously supported but caused TAP plan count mismatches
when combined with the ``--tap`` flag, producing false failures. Single-threaded
mode is reliable and is what CI enforces.

Local Runs and Isolation
~~~~~~~~~~~~~~~~~~~~~~~~

Running ``test/run`` directly on your machine works, but it inherits your shell's
``PATH``. Any tool installed locally (e.g. ``op``, ``herdr``, ``docker``) will be
visible to the tests, which can cause tests to behave differently than they do on CI,
where the runner is a clean environment with only a known set of packages installed.

To reproduce CI conditions exactly, use ``test/run-local``, which builds a minimal
Docker image and runs the tests inside it:

.. code-block:: bash

# Run all tests in a clean container:
test/run-local

# Run a subset:
test/run-local test/completion/op.completion.bats

The image is built on the first run and cached afterwards, so subsequent runs are
fast. The trade-off compared to running ``test/run`` directly is that the first run
takes longer and Docker must be installed.

Writing Tests
-------------
Expand Down
47 changes: 47 additions & 0 deletions test/completion/herdr.completion.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# shellcheck shell=bats

load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash"

function local_setup_file() {
setup_libs "helpers"
load "${BASH_IT?}/lib/completion.bash"
}

function local_setup() {
MOCK_BIN="${BATS_TEST_TMPDIR}/mock-bin"
mkdir -p "${MOCK_BIN}"
_SAVED_PATH="${PATH}"
}

function local_teardown() {
PATH="${_SAVED_PATH}"
complete -r herdr 2> /dev/null || true
}

function _mock_herdr() {
printf '%s\n' \
'#!/usr/bin/env bash' \
'[[ "$*" == "completion bash" ]] && echo "complete -o nospace herdr"' \
> "${MOCK_BIN}/herdr"
chmod +x "${MOCK_BIN}/herdr"
PATH="${MOCK_BIN}:${PATH}"
}

@test "completion herdr: fails to load when herdr is not in PATH" {
PATH="${MOCK_BIN}" run source "${BASH_IT?}/completion/available/herdr.completion.bash"
assert_failure
}

@test "completion herdr: loads successfully when herdr is available" {
_mock_herdr
run source "${BASH_IT?}/completion/available/herdr.completion.bash"
assert_success
}

@test "completion herdr: skips eval when completion is already managed externally" {
_mock_herdr
complete -F : herdr
source "${BASH_IT?}/completion/available/herdr.completion.bash"
run complete -p herdr
assert_output "complete -F : herdr"
}
47 changes: 47 additions & 0 deletions test/completion/op.completion.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# shellcheck shell=bats

load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash"

function local_setup_file() {
setup_libs "helpers"
load "${BASH_IT?}/lib/completion.bash"
}

function local_setup() {
MOCK_BIN="${BATS_TEST_TMPDIR}/mock-bin"
mkdir -p "${MOCK_BIN}"
_SAVED_PATH="${PATH}"
}

function local_teardown() {
PATH="${_SAVED_PATH}"
complete -r op 2> /dev/null || true
}

function _mock_op() {
printf '%s\n' \
'#!/usr/bin/env bash' \
'[[ "$*" == "completion bash" ]] && echo "complete -o nospace op"' \
> "${MOCK_BIN}/op"
chmod +x "${MOCK_BIN}/op"
PATH="${MOCK_BIN}:${PATH}"
}

@test "completion op: fails to load when op is not in PATH" {
PATH="${MOCK_BIN}" run source "${BASH_IT?}/completion/available/op.completion.bash"
assert_failure
}

@test "completion op: loads successfully when op is available" {
_mock_op
run source "${BASH_IT?}/completion/available/op.completion.bash"
assert_success
}

@test "completion op: skips eval when completion is already managed externally" {
_mock_op
complete -F : op
source "${BASH_IT?}/completion/available/op.completion.bash"
run complete -p op
assert_output "complete -F : op"
}
24 changes: 24 additions & 0 deletions test/run-local
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail

IMAGE="bash-it-local-test-runner"
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

# Build the image — idempotent, Docker cache makes subsequent runs instant
docker build --tag "${IMAGE}" - <<'DOCKERFILE'
FROM ubuntu:24.04
RUN apt-get update -q \
&& apt-get install -qy git locales curl iproute2 \
&& locale-gen en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*
ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
DOCKERFILE

# Mirror CI exactly: TEST_JOBS=1 avoids --tap + --jobs TAP count mismatches.
# Pass any arguments through to test/run (e.g. test/completion/op.completion.bats)
exec docker run --rm \
--volume "${REPO_ROOT}:/workspace" \
--workdir /workspace \
--env TEST_JOBS=1 \
"${IMAGE}" \
bash test/run "$@"
Loading