pyenv verification source
Some checks are pending
macos_build / macos_build (3.10) (push) Waiting to run
macos_build / macos_build (3.11) (push) Waiting to run
macos_build / macos_build (3.12) (push) Waiting to run
macos_build / macos_build (3.13) (push) Waiting to run
macos_build / macos_build (3.14) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-14) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-15) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-15-intel) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-26) (push) Waiting to run
pyenv_tests / pyenv_tests (ubuntu-22.04) (push) Waiting to run
pyenv_tests / pyenv_tests (ubuntu-24.04) (push) Waiting to run
ubuntu_build / ubuntu_build (3.10) (push) Waiting to run
ubuntu_build / ubuntu_build (3.11) (push) Waiting to run
ubuntu_build / ubuntu_build (3.12) (push) Waiting to run
ubuntu_build / ubuntu_build (3.13) (push) Waiting to run
ubuntu_build / ubuntu_build (3.14) (push) Waiting to run

This commit is contained in:
2026-05-22 16:45:42 +08:00
commit b622f8abd2
1500 changed files with 110179 additions and 0 deletions

52
test/--version.bats Normal file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bats
load test_helper
_setup() {
export GIT_DIR="${PYENV_TEST_DIR}"
export GIT_WORK_TREE="$GIT_DIR"
git init --quiet
git config user.name "Tester"
git config user.email "tester@test.local"
cd "$PYENV_TEST_DIR"
}
git_commit() {
git commit --quiet --allow-empty -m "empty"
}
@test "default version" {
assert [ ! -e "$PYENV_ROOT" ]
run pyenv---version
assert_success
[[ $output == "pyenv "?.?.* ]]
}
@test "doesn't read version from non-pyenv repo" {
git remote add origin https://github.com/homebrew/homebrew.git
git_commit
git tag v1.0
run pyenv---version
assert_success
[[ $output == "pyenv "?.?.* ]]
}
@test "reads version from git repo" {
git remote add origin https://github.com/pyenv/pyenv.git
git_commit
git tag v0.4.1
git_commit
git_commit
run pyenv---version
assert_success "pyenv 0.4.1-2-g$(git rev-parse --short HEAD)"
}
@test "prints default version if no tags in git repo" {
git remote add origin https://github.com/pyenv/pyenv.git
git_commit
run pyenv---version
[[ $output == "pyenv "?.?.* ]]
}

25
test/Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
ARG BASH
FROM alpine/git:v2.30.0 as bats
ARG BATS_VERSION
RUN git clone https://github.com/bats-core/bats-core.git /root/bats-core \
&& cd /root/bats-core \
&& git checkout "${BATS_VERSION}"
FROM bash:$BASH
# Gnu tools
RUN if [[ "${GNU:-}" == True ]];then \
apk add sed coreutils findutils \
;fi
# Bats
RUN apk add --update parallel ncurses git \
&& mkdir -p ~/.parallel \
&& touch ~/.parallel/will-cite
COPY --from=bats /root/bats-core /root/bats-core
RUN /root/bats-core/install.sh "/usr/local"
# Clean
RUN rm -rf /var/cache/apk/*
# Setup
RUN echo 'source /etc/profile' >> ~/.bashrc
WORKDIR /code/
CMD ["bash"]

76
test/README.md Normal file
View File

@@ -0,0 +1,76 @@
# TEST
---
## Running test suite
Test suite could be launch with `make` by providing the right target depending what you want to achieve.
Under the hood, `pyenv` test suites use `bats` as a test framework and are run on the host or docker depending of the target provided to make.
### Targets
- `test`
- Run the whole test suite on the local host
- `test-docker`
- Run the whole test suite on docker
- Some volumes are used in read-only mode
- `test-unit`
- Run the unit test
- `test-plugin`
- Run the plugin test
- `test-unit-docker-[BASH_VERSION]`
- Run the unit test under **official** bash docker container (alpine/busybox) with the specified bash version if present is in the `Makefile`
- Some volumes are used in read-only mode
- `test-unit-docker-gnu-[BASH_VERSION]`
- Run the unit test under **official** bash docker container (alpine/busybox), completed by **GNU Tools**, with the specified bash version if present is in the `Makefile`
- Some volumes are used in read-only mode
- `test-plugin-docker-[BASH_VERSION]`
- Run the plugin test under **official** bash docker container (alpine/busybox), completed by **GNU Tools**, with the specified bash version if present is in the `Makefile`
- Some volumes are used in read-only mode
- `test-plugin-docker-gnu-[BASH_VERSION]`
- Run the plugin test under **official** bash docker container (alpine/busybox), completed by **GNU Tools**, with the specified bash version if present is in the `Makefile`
- Some volumes are used in read-only mode
## Targeting specific test / test file
By setting some environment variables, it is possible to filtering which test and/or test file who will be tested with bats
- `BATS_FILE_FILTER`
- Run test only with the specified file
- `BATS_TEST_FILTER`
- Run test only who corresponding to the filter provided
### Examples
```bash
$ BATS_TEST_FILTER=".*installed.*" BATS_FILE_FILTER="build.bats" make test-plugin-docker-gnu-3.2.57
build.bats
✓ yaml is installed for python
✓ homebrew is used in Linux if Pyenv is installed with Homebrew
✓ homebrew is not used in Linux if Pyenv is not installed with Homebrew
3 tests, 0 failures
$ BATS_TEST_FILTER=".*installed.*" BATS_FILE_FILTER="build.bats" make test-plugin
build.bats
✓ yaml is installed for python
✓ homebrew is used in Linux if Pyenv is installed with Homebrew
✓ homebrew is not used in Linux if Pyenv is not installed with Homebrew
3 tests, 0 failures
```
## Writing test
To be reproducible, each test use/should use its own `TMPDIR` .
It's achieved by using the environment variable `BATS_TEST_TMPDIR` provided by bats that is automatically deleted at the end of each test. More info [here](https://bats-core.readthedocs.io/en/stable/writing-tests.html#special-variables)
Another variable who could be used to source some file who need to be tested is `BATS_TEST_DIRNAME` who point to the directory in which the bats test file is located.

39
test/commands.bats Normal file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bats
load test_helper
@test "commands" {
run pyenv-commands
assert_success
assert_line "init"
assert_line "rehash"
assert_line "shell"
refute_line "sh-shell"
assert_line "echo"
}
@test "commands --sh" {
run pyenv-commands --sh
assert_success
refute_line "init"
assert_line "shell"
}
@test "commands in path with spaces" {
path="${PYENV_TEST_DIR}/my commands"
cmd="${path}/pyenv-sh-hello"
mkdir -p "$path"
touch "$cmd"
chmod +x "$cmd"
PATH="${path}:$PATH" run pyenv-commands --sh
assert_success
assert_line "hello"
}
@test "commands --no-sh" {
run pyenv-commands --no-sh
assert_success
assert_line "init"
refute_line "shell"
}

51
test/completions.bats Normal file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bats
load test_helper
create_command() {
bin="${PYENV_TEST_DIR}/bin"
mkdir -p "$bin"
echo "$2" > "${bin}/$1"
chmod +x "${bin}/$1"
}
@test "command with no completion support" {
create_command "pyenv-hello" "#!$BASH
echo hello"
run pyenv-completions hello
assert_success "--help"
}
@test "command with completion support" {
create_command "pyenv-hello" "#!$BASH
# Provide pyenv completions
if [[ \$1 = --complete ]]; then
echo hello
else
exit 1
fi"
run pyenv-completions hello
assert_success
assert_output <<OUT
--help
hello
OUT
}
@test "forwards extra arguments" {
create_command "pyenv-hello" "#!$BASH
# provide pyenv completions
if [[ \$1 = --complete ]]; then
shift 1
for arg; do echo \$arg; done
else
exit 1
fi"
run pyenv-completions hello happy world
assert_success
assert_output <<OUT
--help
happy
world
OUT
}

141
test/exec.bats Normal file
View File

@@ -0,0 +1,141 @@
#!/usr/bin/env bats
load test_helper
@test "fails with invalid version" {
bats_require_minimum_version 1.5.0
export PYENV_VERSION="3.4"
run -127 pyenv-exec nonexistent
assert_failure <<EOF
pyenv: version \`3.4' is not installed (set by PYENV_VERSION environment variable)
pyenv: nonexistent: command not found
EOF
}
@test "fails with invalid version set from file" {
bats_require_minimum_version 1.5.0
mkdir -p "$PYENV_TEST_DIR"
cd "$PYENV_TEST_DIR"
echo 2.7 > .python-version
run -127 pyenv-exec nonexistent
assert_failure <<EOF
pyenv: version \`2.7' is not installed (set by $PWD/.python-version)
pyenv: nonexistent: command not found
EOF
}
@test "completes with names of executables" {
export PYENV_VERSION="3.4"
create_alt_executable "fab"
create_alt_executable "python"
pyenv-rehash
run pyenv-completions exec
assert_success
assert_output <<OUT
--help
fab
python
OUT
}
@test "carries original IFS within hooks" {
create_hook exec hello.bash <<SH
hellos=(\$(printf "hello\\tugly world\\nagain"))
echo HELLO="\$(printf ":%s" "\${hellos[@]}")"
SH
export PYENV_VERSION=system
IFS=$' \t\n' run pyenv-exec env
assert_success
assert_line "HELLO=:hello:ugly:world:again"
}
@test "forwards all arguments" {
export PYENV_VERSION="3.4"
create_alt_executable "python" <<SH
#!$BASH
echo \$0
for arg; do
# hack to avoid bash builtin echo which can't output '-e'
printf " %s\\n" "\$arg"
done
SH
run pyenv-exec python -w "/path to/python script.rb" -- extra args
assert_success
assert_output <<OUT
${PYENV_ROOT}/versions/3.4/bin/python
-w
/path to/python script.rb
--
extra
args
OUT
}
@test "sys.executable with system version (#98)" {
create_path_executable "python3" "echo system"
system_python="$(python3 </dev/null)"
assert_equal "${system_python}" "system"
export PYENV_VERSION="custom"
create_alt_executable "python3" "echo custom"
pyenv-rehash
custom_python="$(pyenv-exec python3)"
assert_equal "${custom_python}" "custom"
}
@test 'PATH is not modified with system Python' {
# Create a wrapper executable that verifies PATH.
create_alt_executable_in_version "custom" "python3" <<!
[[ \$PATH == "\${PYENV_ROOT}/versions/custom/bin:"* ]] \
|| { echo "unexpected:\$PATH"; exit 2;}
!
pyenv-rehash
# Path is not modified with system Python.
create_path_executable "python3" "echo \$PATH"
pyenv-rehash
run pyenv-exec python3
assert_success "$PATH"
# Path is modified with custom Python.
PYENV_VERSION=custom run pyenv-exec python3
assert_success
# Path is modified with custom:system Python.
PYENV_VERSION=custom:system run pyenv-exec python3
assert_success
# Path is not modified with system:custom Python.
PYENV_VERSION=system:custom run pyenv-exec python3
assert_success "$PATH"
}
@test "sets/adds to _PYENV_SHIM_PATHS_{PROGRAM} when _PYENV_SHIM_PATH is set, unsets _PYENV_SHIM_PATH" {
progname='123;wacky-prog.name ^%$#'
envvarname="_PYENV_SHIM_PATHS_123_WACKY_PROG_NAME_____"
create_path_executable "$progname" <<!
echo $envvarname="\$$envvarname"
echo _PYENV_SHIM_PATH="\$_PYENV_SHIM_PATH"
!
_PYENV_SHIM_PATH=/unusual/shim/location run pyenv-exec "$progname"
assert_success
assert_output <<!
$envvarname=/unusual/shim/location
_PYENV_SHIM_PATH=
!
eval "export ${envvarname}=/another/shim/location"
_PYENV_SHIM_PATH=/unusual/shim/location run pyenv-exec "$progname"
assert_success
assert_output <<!
$envvarname=/unusual/shim/location:/another/shim/location
_PYENV_SHIM_PATH=
!
}

31
test/global.bats Normal file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bats
load test_helper
@test "default" {
run pyenv-global
assert_success
assert_output "system"
}
@test "read PYENV_ROOT/version" {
mkdir -p "$PYENV_ROOT"
echo "1.2.3" > "$PYENV_ROOT/version"
run pyenv-global
assert_success
assert_output "1.2.3"
}
@test "set PYENV_ROOT/version" {
mkdir -p "$PYENV_ROOT/versions/1.2.3"
run pyenv-global "1.2.3"
assert_success
run pyenv-global
assert_success "1.2.3"
}
@test "fail setting invalid PYENV_ROOT/version" {
mkdir -p "$PYENV_ROOT"
run pyenv-global "1.2.3"
assert_failure "pyenv: version \`1.2.3' not installed"
}

115
test/help.bats Normal file
View File

@@ -0,0 +1,115 @@
#!/usr/bin/env bats
load test_helper
@test "without args shows summary of common commands" {
run pyenv-help
assert_success
assert_line "Usage: pyenv <command> [<args>]"
assert_line "Some useful pyenv commands are:"
}
@test "invalid command" {
run pyenv-help hello
assert_failure "pyenv: no such command \`hello'"
}
@test "shows help for a specific command" {
mkdir -p "${PYENV_TEST_DIR}/bin"
cat > "${PYENV_TEST_DIR}/bin/pyenv-hello" <<SH
#!shebang
# Usage: pyenv hello <world>
# Summary: Says "hello" to you, from pyenv
# This command is useful for saying hello.
echo hello
SH
run pyenv-help hello
assert_success
assert_output <<SH
Usage: pyenv hello <world>
This command is useful for saying hello.
SH
}
@test "replaces missing extended help with summary text" {
mkdir -p "${PYENV_TEST_DIR}/bin"
cat > "${PYENV_TEST_DIR}/bin/pyenv-hello" <<SH
#!shebang
# Usage: pyenv hello <world>
# Summary: Says "hello" to you, from pyenv
echo hello
SH
run pyenv-help hello
assert_success
assert_output <<SH
Usage: pyenv hello <world>
Says "hello" to you, from pyenv
SH
}
@test "extracts only usage" {
mkdir -p "${PYENV_TEST_DIR}/bin"
cat > "${PYENV_TEST_DIR}/bin/pyenv-hello" <<SH
#!shebang
# Usage: pyenv hello <world>
# Summary: Says "hello" to you, from pyenv
# This extended help won't be shown.
echo hello
SH
run pyenv-help --usage hello
assert_success "Usage: pyenv hello <world>"
}
@test "multiline usage section" {
mkdir -p "${PYENV_TEST_DIR}/bin"
cat > "${PYENV_TEST_DIR}/bin/pyenv-hello" <<SH
#!shebang
# Usage: pyenv hello <world>
# pyenv hi [everybody]
# pyenv hola --translate
# Summary: Says "hello" to you, from pyenv
# Help text.
echo hello
SH
run pyenv-help hello
assert_success
assert_output <<SH
Usage: pyenv hello <world>
pyenv hi [everybody]
pyenv hola --translate
Help text.
SH
}
@test "multiline extended help section" {
mkdir -p "${PYENV_TEST_DIR}/bin"
cat > "${PYENV_TEST_DIR}/bin/pyenv-hello" <<SH
#!shebang
# Usage: pyenv hello <world>
# Summary: Says "hello" to you, from pyenv
# This is extended help text.
# It can contain multiple lines.
#
# And paragraphs.
echo hello
SH
run pyenv-help hello
assert_success
assert_output <<SH
Usage: pyenv hello <world>
This is extended help text.
It can contain multiple lines.
And paragraphs.
SH
}

70
test/hooks.bats Normal file
View File

@@ -0,0 +1,70 @@
#!/usr/bin/env bats
load test_helper
@test "prints usage help given no argument" {
run pyenv-hooks
assert_failure "Usage: pyenv hooks <command>"
}
@test "prints list of hooks" {
path1="${PYENV_TEST_DIR}/pyenv.d"
path2="${PYENV_TEST_DIR}/etc/pyenv_hooks"
PYENV_HOOK_PATH="$path1"
create_hook exec "hello.bash"
create_hook exec "ahoy.bash"
create_hook exec "invalid.sh"
create_hook which "boom.bash"
PYENV_HOOK_PATH="$path2"
create_hook exec "bueno.bash"
PYENV_HOOK_PATH="$path1:$path2" run pyenv-hooks exec
assert_success
assert_output <<OUT
${PYENV_TEST_DIR}/pyenv.d/exec/ahoy.bash
${PYENV_TEST_DIR}/pyenv.d/exec/hello.bash
${PYENV_TEST_DIR}/etc/pyenv_hooks/exec/bueno.bash
OUT
}
@test "supports hook paths with spaces" {
path1="${PYENV_TEST_DIR}/my hooks/pyenv.d"
path2="${PYENV_TEST_DIR}/etc/pyenv hooks"
PYENV_HOOK_PATH="$path1"
create_hook exec "hello.bash"
PYENV_HOOK_PATH="$path2"
create_hook exec "ahoy.bash"
PYENV_HOOK_PATH="$path1:$path2" run pyenv-hooks exec
assert_success
assert_output <<OUT
${PYENV_TEST_DIR}/my hooks/pyenv.d/exec/hello.bash
${PYENV_TEST_DIR}/etc/pyenv hooks/exec/ahoy.bash
OUT
}
@test "resolves relative paths" {
PYENV_HOOK_PATH="${PYENV_TEST_DIR}/pyenv.d"
create_hook exec "hello.bash"
mkdir -p "$HOME"
PYENV_HOOK_PATH="${HOME}/../pyenv.d" run pyenv-hooks exec
assert_success "${PYENV_TEST_DIR}/pyenv.d/exec/hello.bash"
}
@test "resolves symlinks" {
path="${PYENV_TEST_DIR}/pyenv.d"
mkdir -p "${path}/exec"
mkdir -p "$HOME"
touch "${HOME}/hola.bash"
ln -s "../../home/hola.bash" "${path}/exec/hello.bash"
touch "${path}/exec/bright.sh"
ln -s "bright.sh" "${path}/exec/world.bash"
PYENV_HOOK_PATH="$path" run pyenv-hooks exec
assert_success
assert_output <<OUT
${HOME}/hola.bash
${PYENV_TEST_DIR}/pyenv.d/exec/bright.sh
OUT
}

254
test/init.bats Executable file
View File

@@ -0,0 +1,254 @@
#!/usr/bin/env bats
load test_helper
@test "creates shims and versions directories" {
assert [ ! -d "${PYENV_ROOT}/shims" ]
assert [ ! -d "${PYENV_ROOT}/versions" ]
run pyenv-init -
assert_success
assert [ -d "${PYENV_ROOT}/shims" ]
assert [ -d "${PYENV_ROOT}/versions" ]
}
@test "auto rehash" {
run pyenv-init -
assert_success
assert_line "command pyenv rehash"
}
@test "auto rehash for --path" {
run pyenv-init --path
assert_success
assert_line "command pyenv rehash"
}
@test "setup shell completions" {
run pyenv-init - bash
assert_success
assert_line "source '${_PYENV_INSTALL_PREFIX}/completions/pyenv.bash'"
}
@test "detect parent shell" {
SHELL=/bin/false run pyenv-init -
assert_success
assert_line "export PYENV_SHELL=bash"
}
@test "detect parent shell from script" {
mkdir -p "$PYENV_TEST_DIR"
cd "$PYENV_TEST_DIR"
cat > myscript.sh <<OUT
#!/bin/sh
eval "\$(pyenv-init -)"
echo \$PYENV_SHELL
OUT
chmod +x myscript.sh
run ./myscript.sh
assert_success "sh"
}
@test "setup shell completions (fish)" {
run pyenv-init - fish
assert_success
assert_line "source '${_PYENV_INSTALL_PREFIX}/completions/pyenv.fish'"
}
@test "fish instructions" {
run pyenv-init fish
assert [ "$status" -eq 1 ]
assert_line 'pyenv init - fish | source'
}
@test "setup shell completions (pwsh)" {
root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
run pyenv-init - pwsh
assert_success
assert_line "iex (gc ${root}/completions/pyenv.pwsh -Raw)"
}
@test "pwsh instructions" {
run pyenv-init pwsh
assert [ "$status" -eq 1 ]
assert_line 'iex ((pyenv init -) -join "`n")'
}
@test "shell detection for installer" {
run pyenv-init --detect-shell
assert_success
assert_line "PYENV_SHELL_DETECT=bash"
}
@test "option to skip rehash" {
run pyenv-init - --no-rehash
assert_success
refute_line "pyenv rehash 2>/dev/null"
}
@test "adds shims to PATH" {
export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
run pyenv-init - bash
assert_success
assert_line 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"'
}
@test "adds shims to PATH (fish)" {
export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
run pyenv-init - fish
assert_success
assert_line "set -gx PATH '${PYENV_ROOT}/shims' \$PATH"
}
@test "adds shims to PATH (pwsh)" {
export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
run pyenv-init - pwsh
assert_success
assert_line '$Env:PATH="'${PYENV_ROOT}'/shims:$Env:PATH"'
}
@test "removes existing shims from PATH" {
OLDPATH="$PATH"
export PATH="${BATS_TEST_DIRNAME}/nonexistent:${PYENV_ROOT}/shims:$PATH"
run bash -e <<!
eval "\$(pyenv-init -)"
echo "\$PATH"
!
assert_success
assert_output "${PYENV_ROOT}/shims:${BATS_TEST_DIRNAME}/nonexistent:${OLDPATH//${PYENV_ROOT}\/shims:/}"
}
@test "removes existing shims from PATH (fish)" {
command -v fish >/dev/null || skip "-- fish not installed"
OLDPATH="$PATH"
export PATH="${BATS_TEST_DIRNAME}/nonexistent:${PYENV_ROOT}/shims:$PATH"
run fish <<!
set -x PATH "$PATH"
pyenv init - | source
echo "\$PATH"
!
assert_success
assert_output "${PYENV_ROOT}/shims:${BATS_TEST_DIRNAME}/nonexistent:${OLDPATH//${PYENV_ROOT}\/shims:/}"
}
@test "removes existing shims from PATH (pwsh)" {
command -v pwsh >/dev/null || skip "-- pwsh not installed"
OLDPATH="$PATH"
export PATH="${BATS_TEST_DIRNAME}/nonexistent:${PYENV_ROOT}/shims:$PATH"
run pwsh -noni -c - <<!
\$Env:PATH="$PATH"
iex ((pyenv init -) -join "\`n")
echo "\$Env:PATH"
!
assert_success
assert_output "${PYENV_ROOT}/shims:${BATS_TEST_DIRNAME}/nonexistent:${OLDPATH//${PYENV_ROOT}\/shims:/}"
}
@test "adds shims to PATH with --no-push-path if they're not on PATH" {
export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
run bash -e <<!
eval "\$(pyenv-init - --no-push-path)"
echo "\$PATH"
!
assert_success
assert_output "${PYENV_ROOT}/shims:${PATH}"
}
@test "adds shims to PATH with --no-push-path if they're not on PATH (fish)" {
command -v fish >/dev/null || skip "-- fish not installed"
export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
run fish <<!
set -x PATH "$PATH"
pyenv-init - --no-push-path| source
echo "\$PATH"
!
assert_success
assert_output "${PYENV_ROOT}/shims:${PATH}"
}
@test "adds shims to PATH with --no-push-path if they're not on PATH (pwsh)" {
command -v pwsh >/dev/null || skip "-- pwsh not installed"
PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
run pwsh -nop -c - <<!
#Powershell silently prepends its own PATH entry upon start
\$Env:PATH="$PATH"
iex ((pyenv init - --no-push-path) -join "\`n")
echo "\$Env:PATH"
!
assert_success
assert_output "${PYENV_ROOT}/shims:${PATH}"
}
@test "doesn't change PATH with --no-push-path if shims are already on PATH" {
export PATH="${BATS_TEST_DIRNAME}/../libexec:${PYENV_ROOT}/shims:/usr/bin:/bin:/usr/local/bin"
run bash -e <<!
eval "\$(pyenv-init - --no-push-path)"
echo "\$PATH"
!
assert_success
assert_output "${PATH}"
}
@test "doesn't change PATH with --no-push-path if shims are already on PATH (fish)" {
command -v fish >/dev/null || skip "-- fish not installed"
export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:${PYENV_ROOT}/shims:/bin:/usr/local/bin"
run fish <<!
set -x PATH "$PATH"
pyenv-init - --no-push-path| source
echo "\$PATH"
!
assert_success
assert_output "${PATH}"
}
@test "doesn't change PATH with --no-push-path if shims are already on PATH (pwsh)" {
command -v pwsh >/dev/null || skip "-- pwsh not installed"
PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:${PYENV_ROOT}/shims:/bin:/usr/local/bin"
run pwsh -nop -c - <<!
#Powershell silently prepends its own PATH entry upon start
\$Env:PATH="$PATH"
iex ((pyenv init - --no-push-path) -join "\`n")
echo "\$Env:PATH"
!
assert_success
assert_output "${PATH}"
}
@test "outputs sh-compatible syntax" {
run pyenv-init - bash
assert_success
assert_line ' case "$command" in'
run pyenv-init - zsh
assert_success
assert_line ' case "$command" in'
}
@test "outputs sh-compatible case syntax" {
create_stub pyenv-commands <<!
echo -e 'activate\ndeactivate\nrehash\nshell'
!
run pyenv-init - bash
assert_success
assert_line ' activate|deactivate|rehash|shell)'
create_stub pyenv-commands <<!
echo
!
run pyenv-init - bash
assert_success
assert_line ' /)'
}
@test "outputs fish-specific syntax (fish)" {
run pyenv-init - fish
assert_success
assert_line ' switch "$command"'
refute_line ' case "$command" in'
}
@test "outputs pwsh-specific syntax (pwsh)" {
run pyenv-init - pwsh
assert_success
refute_line ' switch "$command"'
refute_line ' case "$command" in'
}

130
test/latest.bats Normal file
View File

@@ -0,0 +1,130 @@
#!/usr/bin/env bats
load test_helper
@test "read from installed" {
create_stub pyenv-versions <<!
echo 4.5.6
!
run pyenv-latest 4
assert_success
assert_output <<!
4.5.6
!
}
@test "read from known" {
create_stub python-build <<!
echo 4.5.6
!
run pyenv-latest -k 4
assert_success
assert_output <<!
4.5.6
!
}
@test "installed version not found" {
create_stub pyenv-versions <<!
echo 3.5.6
echo 3.10.8
!
run pyenv-latest 3.8
assert_failure
assert_output <<!
pyenv: no installed versions match the prefix \`3.8'
!
}
@test "known version not found" {
create_stub python-build <<!
echo 3.5.6
echo 3.10.8
!
run pyenv-latest -k 3.8
assert_failure
assert_output <<!
pyenv: no known versions match the prefix \`3.8'
!
}
@test "complete name resolves to itself" {
create_stub pyenv-versions <<!
echo foo
echo foo.bar
!
run pyenv-latest foo
assert_success
assert_output <<!
foo
!
}
@test "sort CPython" {
create_stub pyenv-versions <<!
echo 2.7.18
echo 3.5.6
echo 3.10.8
echo 3.10.6
!
run pyenv-latest 3
assert_success
assert_output <<!
3.10.8
!
}
@test "ignores rolling releases, branch tips, alternative srcs, prereleases, virtualenvs; 't' versions if prefix without 't'" {
create_stub pyenv-versions <<!
echo 3.8.5-dev
echo 3.8.5-src
echo 3.8.5-latest
echo 3.8.5a2
echo 3.8.5b3
echo 3.8.5rc2
echo 3.8.5t
echo 3.8.5b3t
echo 3.8.5rc2t
echo 3.8.1
echo 3.8.1/envs/foo
!
run pyenv-latest 3.8
assert_success
assert_output <<!
3.8.1
!
}
@test "resolves to a 't' version if prefix has 't'" {
create_stub pyenv-versions <<!
echo 3.13.2t
echo 3.13.5
echo 3.13.5t
echo 3.14.6
!
run pyenv-latest 3t
assert_success
assert_output <<!
3.13.5t
!
}
@test "falls back to argument with -b" {
create_stub pyenv-versions
run pyenv-latest -b nonexistent
assert_failure
assert_output <<!
nonexistent
!
}
@test "falls back to argument and succeeds with -f" {
create_stub pyenv-versions
run pyenv-latest -f nonexistent
assert_success
assert_output <<!
nonexistent
!
}

9
test/libexec/pyenv-echo Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Usage: pyenv echo [-F<char>] VAR
if [[ $1 == -F* ]]; then
sep="${1:2}"
echo "${!2}" | tr "${sep:-:}" $'\n'
else
echo "${!1}"
fi

71
test/local.bats Normal file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bats
load test_helper
_setup() {
mkdir -p "${PYENV_TEST_DIR}/myproject"
cd "${PYENV_TEST_DIR}/myproject"
}
@test "no version" {
assert [ ! -e "${PWD}/.python-version" ]
run pyenv-local
assert_failure "pyenv: no local version configured for this directory"
}
@test "local version" {
echo "1.2.3" > .python-version
run pyenv-local
assert_success "1.2.3"
}
@test "discovers version file in parent directory" {
echo "1.2.3" > .python-version
mkdir -p "subdir" && cd "subdir"
run pyenv-local
assert_success "1.2.3"
}
@test "ignores PYENV_DIR" {
echo "1.2.3" > .python-version
mkdir -p "$HOME"
echo "3.4-home" > "${HOME}/.python-version"
PYENV_DIR="$HOME" run pyenv-local
assert_success "1.2.3"
}
@test "sets local version" {
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
run pyenv-local 1.2.3
assert_success ""
assert [ "$(cat .python-version)" = "1.2.3" ]
}
@test "fails to set a nonexistent local version" {
run pyenv-local 1.2.3
assert_failure "pyenv: version \`1.2.3' not installed"
assert [ ! -e .python-version ]
}
@test "sets a nonexistent local version with --force" {
run pyenv-local -f 1.2.3
assert_success ""
assert [ "$(cat .python-version)" = "1.2.3" ]
}
@test "changes local version" {
echo "1.0-pre" > .python-version
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
run pyenv-local
assert_success "1.0-pre"
run pyenv-local 1.2.3
assert_success ""
assert [ "$(cat .python-version)" = "1.2.3" ]
}
@test "unsets local version" {
touch .python-version
run pyenv-local --unset
assert_success ""
assert [ ! -e .python-version ]
}

60
test/pip-rehash.bats Executable file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env bats
load test_helper
copy_src_pyenvd() {
mkdir -p "${PYENV_ROOT}"
cp -r "${BATS_TEST_DIRNAME}/../pyenv.d" "${PYENV_ROOT}"
}
@test "pip-rehash triggered when using 'pip'" {
export PYENV_VERSION="3.7.14"
create_alt_executable "example"
create_alt_executable "pip"
copy_src_pyenvd
run command -v example 2> /dev/null
assert_failure
run pyenv-exec pip install example
assert_success
run command -v example 2> /dev/null
assert_success
}
@test "pip-rehash triggered when using 'pip3'" {
export PYENV_VERSION="3.7.14"
create_alt_executable "example"
create_alt_executable "pip3"
copy_src_pyenvd
run command -v example 2> /dev/null
assert_failure
run pyenv-exec pip3 install example
assert_success
run command -v example 2> /dev/null
assert_success
}
@test "pip-rehash triggered when using 'pip3.x'" {
export PYENV_VERSION="3.7.14"
create_alt_executable "example"
create_alt_executable "pip3.7"
copy_src_pyenvd
run command -v example 2> /dev/null
assert_failure
run pyenv-exec pip3.7 install example
assert_success
run command -v example 2> /dev/null
assert_success
}
@test "pip-rehash triggered when using 'python -m pip install'" {
export PYENV_VERSION="3.7.14"
create_alt_executable "example"
create_alt_executable "python"
copy_src_pyenvd
run command -v example 2> /dev/null
assert_failure
run pyenv-exec python -m pip install example
assert_success
run command -v example 2> /dev/null
assert_success
}

51
test/prefix.bats Normal file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bats
load test_helper
@test "prefix" {
mkdir -p "${PYENV_TEST_DIR}/myproject"
cd "${PYENV_TEST_DIR}/myproject"
echo "1.2.3" > .python-version
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
run pyenv-prefix
assert_success "${PYENV_ROOT}/versions/1.2.3"
}
@test "prefix for invalid version" {
PYENV_VERSION="1.2.3" run pyenv-prefix
assert_failure "pyenv: version \`1.2.3' not installed"
}
@test "prefix for system" {
mkdir -p "${PYENV_TEST_DIR}/bin"
touch "${PYENV_TEST_DIR}/bin/python"
chmod +x "${PYENV_TEST_DIR}/bin/python"
PATH="${PYENV_TEST_DIR}/libexec:$PATH" PYENV_VERSION="system" run pyenv-prefix
assert_success "$PYENV_TEST_DIR"
}
#Arch has Python at sbin as well as bin
@test "prefix for system in sbin" {
mkdir -p "${PYENV_TEST_DIR}/sbin"
touch "${PYENV_TEST_DIR}/sbin/python"
chmod +x "${PYENV_TEST_DIR}/sbin/python"
PATH="${PYENV_TEST_DIR}/sbin:$PATH" PYENV_VERSION="system" run pyenv-prefix
assert_success "$PYENV_TEST_DIR"
}
@test "prefix for system in /" {
mkdir -p "${PYENV_TEST_DIR}/libexec"
cat >"${PYENV_TEST_DIR}/libexec/pyenv-which" <<OUT
#!/bin/sh
echo /bin/python
OUT
chmod +x "${PYENV_TEST_DIR}/libexec/pyenv-which"
PATH="${PYENV_TEST_DIR}/libexec:$PATH" PYENV_VERSION="system" run pyenv-prefix
assert_success "/"
rm -f "${PYENV_TEST_DIR}/libexec/pyenv-which"
}
@test "prefix for invalid system" {
PATH="$(path_without python python2 python3)" run pyenv-prefix system
assert_failure "pyenv: system version not found in PATH"
}

72
test/pyenv.bats Normal file
View File

@@ -0,0 +1,72 @@
#!/usr/bin/env bats
load test_helper
@test "blank invocation" {
run pyenv
assert_failure
assert_line 0 "$(pyenv---version)"
}
@test "invalid command" {
run pyenv does-not-exist
assert_failure
assert_output "pyenv: no such command \`does-not-exist'"
}
@test "default PYENV_ROOT" {
PYENV_ROOT="" HOME=/home/mislav run pyenv root
assert_success
assert_output "/home/mislav/.pyenv"
}
@test "inherited PYENV_ROOT" {
PYENV_ROOT=/opt/pyenv run pyenv root
assert_success
assert_output "/opt/pyenv"
}
@test "default PYENV_DIR" {
run pyenv echo PYENV_DIR
assert_output "$(pwd)"
}
@test "inherited PYENV_DIR" {
dir="${BATS_TEST_TMPDIR}/myproject"
mkdir -p "$dir"
PYENV_DIR="$dir" run pyenv echo PYENV_DIR
assert_output "$dir"
}
@test "invalid PYENV_DIR" {
dir="${BATS_TEST_TMPDIR}/does-not-exist"
assert [ ! -d "$dir" ]
PYENV_DIR="$dir" run pyenv echo PYENV_DIR
assert_failure
assert_output "pyenv: cannot change working directory to \`$dir'"
}
@test "adds its own libexec and plugin bin dirs to PATH" {
mkdir -p "$PYENV_ROOT"/plugins/python-build/bin
mkdir -p "$PYENV_ROOT"/plugins/pyenv-each/bin
run pyenv echo -F: "PATH"
assert_success
assert_line 0 "${BATS_TEST_DIRNAME%/*}/libexec"
assert_line 1 "${PYENV_ROOT}/plugins/python-build/bin"
assert_line 2 "${PYENV_ROOT}/plugins/pyenv-each/bin"
assert_line 3 "${BATS_TEST_DIRNAME%/*}/plugins/python-build/bin"
}
@test "PYENV_HOOK_PATH preserves value from environment" {
PYENV_HOOK_PATH=/my/hook/path:/other/hooks run pyenv echo -F: "PYENV_HOOK_PATH"
assert_success
assert_line 0 "/my/hook/path"
assert_line 1 "/other/hooks"
assert_line 2 "${PYENV_ROOT}/pyenv.d"
}
@test "PYENV_HOOK_PATH includes pyenv built-in plugins" {
unset PYENV_HOOK_PATH
run pyenv echo "PYENV_HOOK_PATH"
assert_success "${PYENV_ROOT}/pyenv.d:${BATS_TEST_DIRNAME%/*}/pyenv.d:/usr/etc/pyenv.d:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks"
}

14
test/pyenv_ext.bats Normal file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bats
load test_helper
@test "prefixes" {
mkdir -p "${PYENV_TEST_DIR}/bin"
touch "${PYENV_TEST_DIR}/bin/python"
chmod +x "${PYENV_TEST_DIR}/bin/python"
mkdir -p "${PYENV_ROOT}/versions/2.7.10"
PYENV_VERSION="system:2.7.10" run pyenv-prefix
assert_success "${PYENV_TEST_DIR}:${PYENV_ROOT}/versions/2.7.10"
PYENV_VERSION="2.7.10:system" run pyenv-prefix
assert_success "${PYENV_ROOT}/versions/2.7.10:${PYENV_TEST_DIR}"
}

178
test/rehash.bats Executable file
View File

@@ -0,0 +1,178 @@
#!/usr/bin/env bats
load test_helper
@test "empty rehash" {
assert [ ! -d "${PYENV_ROOT}/shims" ]
run pyenv-rehash
assert_success ""
assert [ -d "${PYENV_ROOT}/shims" ]
rmdir "${PYENV_ROOT}/shims"
}
@test "non-writable shims directory" {
mkdir -p "${PYENV_ROOT}/shims"
chmod -w "${PYENV_ROOT}/shims"
run pyenv-rehash
assert_failure "pyenv: cannot rehash: ${PYENV_ROOT}/shims isn't writable"
}
@test "rehash in progress" {
export PYENV_REHASH_TIMEOUT=1
mkdir -p "${PYENV_ROOT}/shims"
touch "${PYENV_ROOT}/shims/.pyenv-shim"
#avoid failure due to a localized error message
LANG=C run pyenv-rehash
assert_failure <<!
pyenv: cannot rehash: couldn't acquire lock ${PYENV_ROOT}/shims/.pyenv-shim for 1 seconds. Last error message:
*/pyenv-rehash: line *: ${PYENV_ROOT}/shims/.pyenv-shim: cannot overwrite existing file
!
}
@test "wait until lock acquisition" {
export PYENV_REHASH_TIMEOUT=5
mkdir -p "${PYENV_ROOT}/shims"
touch "${PYENV_ROOT}/shims/.pyenv-shim"
bash -c "sleep 1 && rm -f ${PYENV_ROOT}/shims/.pyenv-shim" &
run pyenv-rehash
assert_success
}
@test "creates shims" {
create_alt_executable_in_version "2.7" "python"
create_alt_executable_in_version "2.7" "fab"
create_alt_executable_in_version "3.4" "python"
create_alt_executable_in_version "3.4" "py.test"
assert [ ! -e "${PYENV_ROOT}/shims/fab" ]
assert [ ! -e "${PYENV_ROOT}/shims/python" ]
assert [ ! -e "${PYENV_ROOT}/shims/py.test" ]
run pyenv-rehash
assert_success ""
run ls "${PYENV_ROOT}/shims"
assert_success
assert_output <<OUT
fab
py.test
python
OUT
}
@test "removes stale shims" {
mkdir -p "${PYENV_ROOT}/shims"
touch "${PYENV_ROOT}/shims/oldshim1"
chmod +x "${PYENV_ROOT}/shims/oldshim1"
create_alt_executable_in_version "3.4" "fab"
create_alt_executable_in_version "3.4" "python"
run pyenv-rehash
assert_success ""
assert [ ! -e "${PYENV_ROOT}/shims/oldshim1" ]
}
@test "binary install locations containing spaces" {
create_alt_executable_in_version "dirname1 p247" "python"
create_alt_executable_in_version "dirname2 preview1" "py.test"
assert [ ! -e "${PYENV_ROOT}/shims/python" ]
assert [ ! -e "${PYENV_ROOT}/shims/py.test" ]
run pyenv-rehash
assert_success ""
run ls "${PYENV_ROOT}/shims"
assert_success
assert_output <<OUT
py.test
python
OUT
}
@test "carries original IFS within hooks" {
create_hook rehash hello.bash <<SH
hellos=(\$(printf "hello\\tugly world\\nagain"))
echo HELLO="\$(printf ":%s" "\${hellos[@]}")"
exit
SH
IFS=$' \t\n' run pyenv-rehash
assert_success
assert_output "HELLO=:hello:ugly:world:again"
}
@test "sh-rehash in bash" {
create_alt_executable_in_version "3.4" "python"
PYENV_SHELL=bash run pyenv-sh-rehash
assert_success "command pyenv rehash
hash -r 2>/dev/null || true"
}
@test "sh-rehash in bash (integration)" {
create_alt_executable_in_version "3.4" "python"
PYENV_SHELL=bash run eval "$(pyenv-sh-rehash)"
assert_success
assert [ -x "${PYENV_ROOT}/shims/python" ]
}
@test "sh-rehash in fish" {
create_alt_executable_in_version "3.4" "python"
PYENV_SHELL=fish run pyenv-sh-rehash
assert_success "command pyenv rehash"
}
@test "sh-rehash in fish (integration)" {
command -v fish >/dev/null || skip "-- fish not installed"
create_alt_executable_in_version "3.4" "python"
PYENV_SHELL=fish fish -Nc "source (pyenv-sh-rehash | psub)"
assert_success
assert [ -x "${PYENV_ROOT}/shims/python" ]
}
@test "sh-rehash in pwsh" {
create_alt_executable_in_version "3.4" "python"
PYENV_SHELL=pwsh run pyenv-sh-rehash
assert_success "& (get-command pyenv -commandtype application) rehash"
}
@test "sh-rehash in pwsh (integration)" {
command -v pwsh >/dev/null || skip "-- pwsh not installed"
assert [ ! -x "${PYENV_ROOT}/shims/python" ]
create_alt_executable_in_version "3.4" "python"
run pwsh -nop -c -<<'!'
$ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $true
iex ((& pyenv init - pwsh) -join "`n")
& pyenv rehash
!
assert_success ""
assert [ -x "${PYENV_ROOT}/shims/python" ]
}
@test "shim sets _PYENV_SHIM_PATH when linked from elsewhere" {
export PYENV_VERSION="custom"
create_alt_executable python3
#must stub pyenv before rehash 'cuz the path is hardcoded into shims
create_stub pyenv <<!
[[ \$1 == 'exec' ]] && \
echo _PYENV_SHIM_PATH="\$_PYENV_SHIM_PATH"
!
pyenv-rehash
mkdir -p "${PYENV_TEST_DIR}/alt-shim"
ln -s "${PYENV_ROOT}/shims/python3" "${PYENV_TEST_DIR}/alt-shim/python3"
run "${PYENV_TEST_DIR}/alt-shim/python3"
assert_success
assert_output <<!
_PYENV_SHIM_PATH=${PYENV_TEST_DIR}/alt-shim
!
run python3
assert_success
assert_output <<!
_PYENV_SHIM_PATH=
!
}

9
test/run Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
if [ -n "$PYENV_NATIVE_EXT" ]; then
src/configure
make -C src
fi
exec bats ${CI:+--tap} ${BATS_TEST_FILTER:+--filter "${BATS_TEST_FILTER}"} test/${BATS_FILE_FILTER}

119
test/shell.bats Normal file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env bats
load test_helper
@test "shell integration disabled" {
run pyenv shell
assert_failure "pyenv: shell integration not enabled. Run \`pyenv init' for instructions."
}
@test "shell integration enabled" {
eval "$(pyenv init -)"
run pyenv shell
assert_success "pyenv: no shell-specific version configured"
}
@test "no shell version" {
mkdir -p "${PYENV_TEST_DIR}/myproject"
cd "${PYENV_TEST_DIR}/myproject"
echo "1.2.3" > .python-version
PYENV_VERSION="" run pyenv-sh-shell
assert_failure "pyenv: no shell-specific version configured"
}
@test "shell version" {
PYENV_SHELL=bash PYENV_VERSION="1.2.3" run pyenv-sh-shell
assert_success 'echo "$PYENV_VERSION"'
}
@test "shell version (fish)" {
PYENV_SHELL=fish PYENV_VERSION="1.2.3" run pyenv-sh-shell
assert_success 'echo "$PYENV_VERSION"'
}
@test "shell version (pwsh)" {
PYENV_SHELL=pwsh PYENV_VERSION="1.2.3" run pyenv-sh-shell
assert_success 'echo "$PYENV_VERSION"'
}
@test "shell revert" {
PYENV_SHELL=bash run pyenv-sh-shell -
assert_success
assert_line 0 'if [ -n "${PYENV_VERSION_OLD+x}" ]; then'
}
@test "shell revert (fish)" {
PYENV_SHELL=fish run pyenv-sh-shell -
assert_success
assert_line 0 'if set -q PYENV_VERSION_OLD'
}
@test "shell revert (pwsh)" {
PYENV_SHELL=pwsh run pyenv-sh-shell -
assert_success
assert_line 0 'if ( Get-Item -Path Env:\PYENV_VERSION* ) {'
}
@test "shell unset" {
PYENV_SHELL=bash run pyenv-sh-shell --unset
assert_success
assert_output <<OUT
PYENV_VERSION_OLD="\${PYENV_VERSION-}"
unset PYENV_VERSION
OUT
}
@test "shell unset (fish)" {
PYENV_SHELL=fish run pyenv-sh-shell --unset
assert_success
assert_output <<OUT
set -gu PYENV_VERSION_OLD "\$PYENV_VERSION"
set -e PYENV_VERSION
OUT
}
@test "shell unset (pwsh)" {
PYENV_SHELL=pwsh run pyenv-sh-shell --unset
assert_success
assert_output <<OUT
\$Env:PYENV_VERSION, \$Env:PYENV_VERSION_OLD = \$null, \$Env:PYENV_VERSION
OUT
}
@test "shell change invalid version" {
run pyenv-sh-shell 1.2.3
assert_failure
assert_output <<SH
pyenv: version \`1.2.3' not installed
false
SH
}
@test "shell change version" {
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
PYENV_SHELL=bash run pyenv-sh-shell 1.2.3
assert_success
assert_output <<OUT
PYENV_VERSION_OLD="\${PYENV_VERSION-}"
export PYENV_VERSION="1.2.3"
OUT
}
@test "shell change version (fish)" {
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
PYENV_SHELL=fish run pyenv-sh-shell 1.2.3
assert_success
assert_output <<OUT
set -gu PYENV_VERSION_OLD "\$PYENV_VERSION"
set -gx PYENV_VERSION "1.2.3"
OUT
}
@test "shell change version (pwsh)" {
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
PYENV_SHELL=pwsh run pyenv-sh-shell 1.2.3
assert_success
assert_output <<OUT
\$Env:PYENV_VERSION, \$Env:PYENV_VERSION_OLD = "1.2.3", \$Env:PYENV_VERSION
OUT
}

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bats
load test_helper
@test "shims linked from elsewhere are chained, other programs at the same paths are unaffected (integration)" {
bats_require_minimum_version 1.5.0
progname=shimmed_program
called_progname=another_program
create_alt_executable_in_version "custom" "$progname" <<!
echo "called from \$0"
pyenv-exec "$called_progname"
!
pyenv-rehash
PATH="$(path_without "$progname" "$called_progname")"
for disguised_shim_path in "$BATS_TEST_TMPDIR/"{weird-location,even/weirder/location}; do
mkdir -p "$disguised_shim_path"
ln -s "${PYENV_ROOT}/shims/$progname" "$disguised_shim_path/$progname"
PATH="$PATH:$disguised_shim_path"
done
create_executable "$disguised_shim_path" "$called_progname" <<!
echo "convoluted call success!"
!
real_path="$BATS_TEST_TMPDIR/real-location"
mkdir -p "$real_path"
ln -s "${PYENV_ROOT}/versions/custom/bin/$progname" "$real_path/$progname"
PATH="$PATH:$real_path"
run "$progname"
assert_success
assert_output <<!
called from $real_path/$progname
convoluted call success!
!
rm "$real_path/$progname"
run -127 "$progname"
assert_failure
assert_line 0 "pyenv: shimmed_program: command not found"
}

29
test/shims.bats Normal file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bats
load test_helper
@test "no shims" {
run pyenv-shims
assert_success
assert [ -z "$output" ]
}
@test "shims" {
mkdir -p "${PYENV_ROOT}/shims"
touch "${PYENV_ROOT}/shims/python"
touch "${PYENV_ROOT}/shims/irb"
run pyenv-shims
assert_success
assert_line "${PYENV_ROOT}/shims/python"
assert_line "${PYENV_ROOT}/shims/irb"
}
@test "shims --short" {
mkdir -p "${PYENV_ROOT}/shims"
touch "${PYENV_ROOT}/shims/python"
touch "${PYENV_ROOT}/shims/irb"
run pyenv-shims --short
assert_success
assert_line "irb"
assert_line "python"
}

195
test/test_helper.bash Normal file
View File

@@ -0,0 +1,195 @@
unset PYENV_VERSION
unset PYENV_DIR
setup() {
export _PYENV_INSTALL_PREFIX="${BATS_TEST_DIRNAME%/*}"
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
if ! enable -f "${_PYENV_INSTALL_PREFIX}"/libexec/pyenv-realpath.dylib realpath 2>/dev/null; then
if [ -n "$PYENV_NATIVE_EXT" ]; then
echo "pyenv: failed to load \`realpath' builtin" >&2
exit 1
fi
fi
local bats_test_tmpdir="$(realpath "${BATS_TEST_TMPDIR}")"
if [ -z "${bats_test_tmpdir}" ];then
# Use readlink if running in a container instead of realpath lib
bats_test_tmpdir="$(readlink -f "${BATS_TEST_TMPDIR}")"
fi
# update BATS_TEST_TMPDIR discover by realpath/readlink to avoid "//"
export BATS_TEST_TMPDIR="${bats_test_tmpdir}"
export PYENV_TEST_DIR="${BATS_TEST_TMPDIR}/pyenv"
export PYENV_ROOT="${PYENV_TEST_DIR}/root"
export HOME="${PYENV_TEST_DIR}/home"
export PYENV_HOOK_PATH="${PYENV_ROOT}/pyenv.d"
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
PATH="${PYENV_TEST_DIR}/bin:$PATH"
PATH="${_PYENV_INSTALL_PREFIX}/libexec:$PATH"
PATH="${BATS_TEST_DIRNAME}/libexec:$PATH"
PATH="${PYENV_ROOT}/shims:$PATH"
PATH="${BATS_TEST_TMPDIR}/stubs:$PATH"
for xdg_var in `env 2>/dev/null | grep ^XDG_ | cut -d= -f1`; do unset "$xdg_var"; done
unset xdg_var
# Workaround for Powershell. When tests are run from a terminal,
# and running a script fron a here-document,
# Powershell 7.5.4 erroneously prints ANSI escape sequences
# even if its output is redirected, breaking the comparison logic
export NO_COLOR=1
# If test specific setup exist, run it
if [[ $(type -t _setup) == function ]];then
_setup
fi
}
flunk() {
{ if [ "$#" -eq 0 ]; then cat -
else echo "$@"
fi
} | sed "s:${PYENV_TEST_DIR}:TEST_DIR:g" >&2
return 1
}
assert_success() {
if [ "$status" -ne 0 ]; then
flunk "command failed with exit status $status" $'\n'\
"output: $output"
elif [ "$#" -gt 0 ]; then
assert_output "$1"
fi
}
assert_failure() {
if [ "$status" -eq 0 ]; then
flunk "expected failed exit status" $'\n'\
"output: $output"
elif [ "$#" -gt 0 ]; then
assert_output "$1"
fi
}
assert_equal() {
if [ "$1" != "$2" ]; then
{ echo "expected: \`$1'"
echo "actual: \`$2'"
} | flunk
fi
}
assert_output() {
local expected
if [ $# -eq 0 ]; then expected="$(cat -)"
else expected="$1"
fi
assert_equal "$expected" "$output"
}
assert_line() {
if [ "$1" -ge 0 ] 2>/dev/null; then
assert_equal "$2" "${lines[$1]}"
else
local line
for line in "${lines[@]}"; do
if [ "$line" = "$1" ]; then return 0; fi
done
flunk "expected line \`$1'" $'\n'\
"output: $output"
fi
}
refute_line() {
if [ "$1" -ge 0 ] 2>/dev/null; then
local num_lines="${#lines[@]}"
if [ "$1" -lt "$num_lines" ]; then
flunk "output has $num_lines lines"
fi
else
local line
for line in "${lines[@]}"; do
if [ "$line" = "$1" ]; then
flunk "expected to not find line \`$line'" $'\n'\
"output: $output"
fi
done
fi
}
assert() {
if ! "$@"; then
flunk "failed: $@"
fi
}
# Output a modified PATH that ensures that the given executable is not present,
# but in which system utils necessary for pyenv operation are still available.
path_without() {
local path=":${PATH}:"
for exe; do
local found alt util
for found in $(PATH="$path" type -aP "$exe"); do
found="${found%/*}"
if [ "$found" != "${PYENV_ROOT}/shims" ]; then
alt="${PYENV_TEST_DIR}/$(echo "${found#/}" | tr '/' '-')"
mkdir -p "$alt"
for util in bash head cut readlink greadlink tr sed xargs basename sort; do
if [ -x "${found}/$util" ]; then
ln -s "${found}/$util" "${alt}/$util"
fi
done
path="${path/:${found}:/:${alt}:}"
fi
done
done
path="${path#:}"
path="${path%:}"
echo "$path"
}
create_path_executable() {
create_executable "${PYENV_TEST_DIR}/bin" "$@"
}
create_alt_executable() {
create_alt_executable_in_version "${PYENV_VERSION}" "$@"
}
create_alt_executable_in_version() {
local version="${1:?}"
shift 1
create_executable "${PYENV_ROOT}/versions/$version/bin" "$@"
}
create_stub() {
create_executable "${BATS_TEST_TMPDIR}/stubs" "$@"
}
create_executable() {
local bin="${1:?}"
local name="${2:?}"
shift 2
mkdir -p "$bin"
local payload
# Bats doesn't redirect stdin
if [[ $# -eq 0 && ! -t 0 ]]; then
payload="$(cat -)"
else
payload="$(printf '%s\n' "$@")"
fi
if [[ $payload != "#!/"* ]]; then
payload="#!$BASH"$'\n'"$payload"
fi
echo "$payload" > "${bin}/$name"
chmod +x "${bin}/$name"
}
create_hook() {
mkdir -p "${PYENV_HOOK_PATH}/$1"
touch "${PYENV_HOOK_PATH}/$1/$2"
if [ ! -t 0 ]; then
cat > "${PYENV_HOOK_PATH}/$1/$2"
fi
}

118
test/version-file-read.bats Normal file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bats
load test_helper
_setup() {
mkdir -p "${PYENV_TEST_DIR}/myproject"
cd "${PYENV_TEST_DIR}/myproject"
}
@test "fails without arguments" {
run pyenv-version-file-read
assert_failure ""
}
@test "fails for invalid file" {
run pyenv-version-file-read "non-existent"
assert_failure ""
}
@test "fails for blank file" {
echo > my-version
run pyenv-version-file-read my-version
assert_failure ""
}
@test "reads simple version file" {
cat > my-version <<<"3.3.5"
run pyenv-version-file-read my-version
assert_success "3.3.5"
}
@test "ignores leading spaces" {
cat > my-version <<<" 3.3.5"
run pyenv-version-file-read my-version
assert_success "3.3.5"
}
@test "reads only the first word from file" {
cat > my-version <<<"3.3.5 2.7.6 hi"
run pyenv-version-file-read my-version
assert_success "3.3.5"
}
@test "loads *not* only the first line in file" {
cat > my-version <<IN
2.7.6 one
3.3.5 two
IN
run pyenv-version-file-read my-version
assert_success "2.7.6:3.3.5"
}
@test "ignores leading blank lines" {
cat > my-version <<IN
3.3.5
IN
run pyenv-version-file-read my-version
assert_success "3.3.5"
}
@test "handles the file with no trailing newline" {
echo -n "2.7.6" > my-version
run pyenv-version-file-read my-version
assert_success "2.7.6"
}
@test "ignores carriage returns" {
cat > my-version <<< $'3.3.5\r'
run pyenv-version-file-read my-version
assert_success "3.3.5"
}
@test "skips comment lines" {
cat > my-version <<IN
3.9.3
3.8.9
# 3.4.0
#3.3.7
2.7.16
IN
run pyenv-version-file-read my-version
assert_success "3.9.3:3.8.9:2.7.16"
}
@test "skips \`..' relative path traversal" {
echo '..' > my-version
run pyenv-version-file-read my-version
assert_failure "pyenv: invalid version \`..' ignored in \`my-version'"
}
@test "skips glob path traversal" {
cat > my-version <<IN
../*
3.9.3
IN
run pyenv-version-file-read my-version
assert_success <<OUT
pyenv: invalid version \`../\*' ignored in \`my-version'
3.9.3
OUT
}
@test "allows relative paths that exist and stay within versions" {
venv=3.10.3/envs/../test
mkdir -p "${PYENV_ROOT}/versions/${venv}"
echo -n "${venv}" > my-version
run pyenv-version-file-read my-version
assert_success "${venv}"
}
@test "skips relative paths that lead outside of versions" {
venv=../3.10.3/envs/test
mkdir -p "${PYENV_ROOT}/versions/${venv}"
echo -n "${venv}" > my-version
run pyenv-version-file-read my-version
assert_failure
}

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env bats
load test_helper
_setup() {
mkdir -p "${PYENV_TEST_DIR}"
cd "$PYENV_TEST_DIR"
}
@test "invocation without 2 arguments prints usage" {
run pyenv-version-file-write
assert_failure "Usage: pyenv version-file-write [-f|--force] <file> <version> [...]"
run pyenv-version-file-write "one" ""
assert_failure
}
@test "setting nonexistent version fails" {
assert [ ! -e ".python-version" ]
run pyenv-version-file-write ".python-version" "2.7.6"
assert_failure "pyenv: version \`2.7.6' not installed"
assert [ ! -e ".python-version" ]
}
@test "setting nonexistent version succeeds with force" {
assert [ ! -e ".python-version" ]
run pyenv-version-file-write --force ".python-version" "2.7.6"
assert_success
assert [ -e ".python-version" ]
}
@test "writes value to arbitrary file" {
mkdir -p "${PYENV_ROOT}/versions/2.7.6"
assert [ ! -e "my-version" ]
run pyenv-version-file-write "${PWD}/my-version" "2.7.6"
assert_success ""
assert [ "$(cat my-version)" = "2.7.6" ]
}

75
test/version-file.bats Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env bats
load test_helper
_setup() {
mkdir -p "${PYENV_TEST_DIR}"
cd "$PYENV_TEST_DIR"
}
create_file() {
mkdir -p "$(dirname "$1")"
echo "system" > "$1"
}
@test "detects global 'version' file" {
create_file "${PYENV_ROOT}/version"
run pyenv-version-file
assert_success "${PYENV_ROOT}/version"
}
@test "prints global file if no version files exist" {
assert [ ! -e "${PYENV_ROOT}/version" ]
assert [ ! -e ".python-version" ]
run pyenv-version-file
assert_success "${PYENV_ROOT}/version"
}
@test "in current directory" {
create_file ".python-version"
run pyenv-version-file
assert_success "${PYENV_TEST_DIR}/.python-version"
}
@test "in parent directory" {
create_file ".python-version"
mkdir -p project
cd project
run pyenv-version-file
assert_success "${PYENV_TEST_DIR}/.python-version"
}
@test "topmost file has precedence" {
create_file ".python-version"
create_file "project/.python-version"
cd project
run pyenv-version-file
assert_success "${PYENV_TEST_DIR}/project/.python-version"
}
@test "PYENV_DIR has precedence over PWD" {
create_file "widget/.python-version"
create_file "project/.python-version"
cd project
PYENV_DIR="${PYENV_TEST_DIR}/widget" run pyenv-version-file
assert_success "${PYENV_TEST_DIR}/widget/.python-version"
}
@test "PWD is searched if PYENV_DIR yields no results" {
mkdir -p "widget/blank"
create_file "project/.python-version"
cd project
PYENV_DIR="${PYENV_TEST_DIR}/widget/blank" run pyenv-version-file
assert_success "${PYENV_TEST_DIR}/project/.python-version"
}
@test "finds version file in target directory" {
create_file "project/.python-version"
run pyenv-version-file "${PWD}/project"
assert_success "${PYENV_TEST_DIR}/project/.python-version"
}
@test "fails when no version file in target directory" {
run pyenv-version-file "$PWD"
assert_failure ""
}

141
test/version-name.bats Normal file
View File

@@ -0,0 +1,141 @@
#!/usr/bin/env bats
load test_helper
create_version() {
mkdir -p "${PYENV_ROOT}/versions/$1"
}
_setup() {
mkdir -p "${PYENV_TEST_DIR}"
cd "$PYENV_TEST_DIR"
}
@test "no version selected" {
assert [ ! -d "${PYENV_ROOT}/versions" ]
run pyenv-version-name
assert_success "system"
}
@test "system version is not checked for existence" {
PYENV_VERSION=system run pyenv-version-name
assert_success "system"
}
@test "PYENV_VERSION can be overridden by hook" {
create_version "2.7.11"
create_version "3.5.1"
create_hook version-name test.bash <<<"PYENV_VERSION=3.5.1"
PYENV_VERSION=2.7.11 run pyenv-version-name
assert_success "3.5.1"
}
@test "carries original IFS within hooks" {
create_hook version-name hello.bash <<SH
hellos=(\$(printf "hello\\tugly world\\nagain"))
echo HELLO="\$(printf ":%s" "\${hellos[@]}")"
SH
export PYENV_VERSION=system
IFS=$' \t\n' run pyenv-version-name env
assert_success
assert_line "HELLO=:hello:ugly:world:again"
}
@test "PYENV_VERSION has precedence over local" {
create_version "2.7.11"
create_version "3.5.1"
cat > ".python-version" <<<"2.7.11"
run pyenv-version-name
assert_success "2.7.11"
PYENV_VERSION=3.5.1 run pyenv-version-name
assert_success "3.5.1"
}
@test "local file has precedence over global" {
create_version "2.7.11"
create_version "3.5.1"
cat > "${PYENV_ROOT}/version" <<<"2.7.11"
run pyenv-version-name
assert_success "2.7.11"
cat > ".python-version" <<<"3.5.1"
run pyenv-version-name
assert_success "3.5.1"
}
@test "missing version" {
PYENV_VERSION=1.2 run pyenv-version-name
assert_failure "pyenv: version \`1.2' is not installed (set by PYENV_VERSION environment variable)"
}
@test "missing version with --force" {
PYENV_VERSION=1.2 run pyenv-version-name -f
assert_success "1.2"
}
@test "one missing version (second missing)" {
create_version "3.5.1"
PYENV_VERSION="3.5.1:1.2" run pyenv-version-name
assert_failure
assert_output <<OUT
pyenv: version \`1.2' is not installed (set by PYENV_VERSION environment variable)
3.5.1
OUT
}
@test "one missing version (first missing)" {
create_version "3.5.1"
PYENV_VERSION="1.2:3.5.1" run pyenv-version-name
assert_failure
assert_output <<OUT
pyenv: version \`1.2' is not installed (set by PYENV_VERSION environment variable)
3.5.1
OUT
}
pyenv-version-name-without-stderr() {
pyenv-version-name 2>/dev/null
}
@test "one missing version (without stderr)" {
create_version "3.5.1"
PYENV_VERSION="1.2:3.5.1" run pyenv-version-name-without-stderr
assert_failure
assert_output <<OUT
3.5.1
OUT
}
@test "version with prefix in name" {
create_version "2.7.11"
cat > ".python-version" <<<"python-2.7.11"
run pyenv-version-name
assert_success
assert_output "2.7.11"
}
@test "falls back to pyenv-latest" {
create_version "2.7.11"
PYENV_VERSION="2.7" run pyenv-version-name
assert_success
assert_output "2.7.11"
}
@test "pyenv-latest fallback with prefix in name" {
create_version "3.12.6"
PYENV_VERSION="python-3.12" run pyenv-version-name
assert_success
assert_output "3.12.6"
}
@test "pyenv version started by python-" {
create_version "python-3.12.6"
PYENV_VERSION="python-3.12.6" run pyenv-version-name
assert_success
assert_output "python-3.12.6"
}

56
test/version-origin.bats Normal file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bats
load test_helper
_setup() {
mkdir -p "${PYENV_TEST_DIR}"
cd "$PYENV_TEST_DIR"
}
@test "reports global file even if it doesn't exist" {
assert [ ! -e "${PYENV_ROOT}/version" ]
run pyenv-version-origin
assert_success "${PYENV_ROOT}/version"
}
@test "detects global file" {
mkdir -p "$PYENV_ROOT"
touch "${PYENV_ROOT}/version"
run pyenv-version-origin
assert_success "${PYENV_ROOT}/version"
}
@test "detects PYENV_VERSION" {
PYENV_VERSION=1 run pyenv-version-origin
assert_success "PYENV_VERSION environment variable"
}
@test "detects local file" {
echo "system" > .python-version
run pyenv-version-origin
assert_success "${PWD}/.python-version"
}
@test "reports from hook" {
create_hook version-origin test.bash <<<"PYENV_VERSION_ORIGIN=plugin"
PYENV_VERSION=1 run pyenv-version-origin
assert_success "plugin"
}
@test "carries original IFS within hooks" {
create_hook version-origin hello.bash <<SH
hellos=(\$(printf "hello\\tugly world\\nagain"))
echo HELLO="\$(printf ":%s" "\${hellos[@]}")"
SH
export PYENV_VERSION=system
IFS=$' \t\n' run pyenv-version-origin env
assert_success
assert_line "HELLO=:hello:ugly:world:again"
}
@test "doesn't inherit PYENV_VERSION_ORIGIN from environment" {
PYENV_VERSION_ORIGIN=ignored run pyenv-version-origin
assert_success "${PYENV_ROOT}/version"
}

81
test/version.bats Normal file
View File

@@ -0,0 +1,81 @@
#!/usr/bin/env bats
load test_helper
create_version() {
mkdir -p "${PYENV_ROOT}/versions/$1"
}
_setup() {
mkdir -p "${PYENV_ROOT}"
cd "$PYENV_TEST_DIR"
}
@test "no version selected" {
assert [ ! -d "${PYENV_ROOT}/versions" ]
run pyenv-version
assert_success "system (set by ${PYENV_ROOT}/version)"
}
@test "set by PYENV_VERSION" {
create_version "3.3.3"
PYENV_VERSION=3.3.3 run pyenv-version
assert_success "3.3.3 (set by PYENV_VERSION environment variable)"
}
@test "set by local file" {
create_version "3.3.3"
cat > ".python-version" <<<"3.3.3"
run pyenv-version
assert_success "3.3.3 (set by ${PWD}/.python-version)"
}
@test "set by global file" {
create_version "3.3.3"
cat > "${PYENV_ROOT}/version" <<<"3.3.3"
run pyenv-version
assert_success "3.3.3 (set by ${PYENV_ROOT}/version)"
}
@test "set by PYENV_VERSION, one missing" {
create_version "3.3.3"
PYENV_VERSION=3.3.3:1.2 run pyenv-version
assert_failure
assert_output <<OUT
pyenv: version \`1.2' is not installed (set by PYENV_VERSION environment variable)
3.3.3 (set by PYENV_VERSION environment variable)
OUT
}
@test "set by PYENV_VERSION, two missing" {
create_version "3.3.3"
PYENV_VERSION=3.4.2:3.3.3:1.2 run pyenv-version
assert_failure
assert_output <<OUT
pyenv: version \`3.4.2' is not installed (set by PYENV_VERSION environment variable)
pyenv: version \`1.2' is not installed (set by PYENV_VERSION environment variable)
3.3.3 (set by PYENV_VERSION environment variable)
OUT
}
pyenv-version-without-stderr() {
pyenv-version 2>/dev/null
}
@test "set by PYENV_VERSION, one missing (stderr filtered)" {
create_version "3.3.3"
PYENV_VERSION=3.4.2:3.3.3 run pyenv-version-without-stderr
assert_failure
assert_output <<OUT
3.3.3 (set by PYENV_VERSION environment variable)
OUT
}
@test "--bare prints just the name" {
create_version "3.3.3"
PYENV_VERSION=3.3.3 run pyenv-version --bare
assert_success
assert_output <<OUT
3.3.3
OUT
}

273
test/versions.bats Normal file
View File

@@ -0,0 +1,273 @@
#!/usr/bin/env bats
load test_helper
create_version() {
mkdir -p "${PYENV_ROOT}/versions/$1"
}
create_alias() {
mkdir -p "${PYENV_ROOT}/versions"
ln -s "$2" "${PYENV_ROOT}/versions/$1"
}
create_external_version() {
mkdir -p "$PYENV_TEST_DIR/${1:?}"
create_alias "${1:?}" "$PYENV_TEST_DIR/${1:?}"
}
_setup() {
mkdir -p "$PYENV_TEST_DIR"
cd "$PYENV_TEST_DIR"
}
stub_system_python() {
local stub="${PYENV_TEST_DIR}/bin/python"
mkdir -p "$(dirname "$stub")"
touch "$stub" && chmod +x "$stub"
}
@test "no versions installed" {
stub_system_python
assert [ ! -d "${PYENV_ROOT}/versions" ]
run pyenv-versions
assert_success "* system (set by ${PYENV_ROOT}/version)"
}
@test "not even system python available" {
PATH="$(path_without python python2 python3)" run pyenv-versions
assert_failure
assert_output "Warning: no Python detected on the system"
}
@test "bare output no versions installed" {
assert [ ! -d "${PYENV_ROOT}/versions" ]
run pyenv-versions --bare
assert_success ""
}
@test "single version installed" {
stub_system_python
create_version "3.3"
run pyenv-versions
assert_success
assert_output <<OUT
* system (set by ${PYENV_ROOT}/version)
3.3
OUT
}
@test "single version bare" {
create_version "3.3"
run pyenv-versions --bare
assert_success "3.3"
}
@test "multiple versions and envs" {
stub_system_python
create_version "2.7.6"
create_version "3.4.0"
create_version "3.4.0/envs/foo"
create_version "3.4.0/envs/bar"
create_version "3.5.2"
run pyenv-versions
assert_success
assert_output <<OUT
* system (set by ${PYENV_ROOT}/version)
2.7.6
3.4.0
3.4.0/envs/bar
3.4.0/envs/foo
3.5.2
OUT
}
@test "skips envs with --skip-envs" {
create_version "3.3.3"
create_version "3.4.0"
create_version "3.4.0/envs/foo"
create_version "3.4.0/envs/bar"
create_version "3.5.0"
run pyenv-versions --skip-envs
assert_success <<OUT
* system (set by ${PYENV_ROOT}/version)
3.3.3
3.4.0
3.5.0
OUT
}
@test "indicates current version" {
stub_system_python
create_version "3.3.3"
create_version "3.4.0"
PYENV_VERSION=3.3.3 run pyenv-versions
assert_success
assert_output <<OUT
system
* 3.3.3 (set by PYENV_VERSION environment variable)
3.4.0
OUT
}
@test "bare doesn't indicate current version" {
create_version "3.3.3"
create_version "3.4.0"
PYENV_VERSION=3.3.3 run pyenv-versions --bare
assert_success
assert_output <<OUT
3.3.3
3.4.0
OUT
}
@test "globally selected version" {
stub_system_python
create_version "3.3.3"
create_version "3.4.0"
cat > "${PYENV_ROOT}/version" <<<"3.3.3"
run pyenv-versions
assert_success
assert_output <<OUT
system
* 3.3.3 (set by ${PYENV_ROOT}/version)
3.4.0
OUT
}
@test "per-project version" {
stub_system_python
create_version "3.3.3"
create_version "3.4.0"
cat > ".python-version" <<<"3.3.3"
run pyenv-versions
assert_success
assert_output <<OUT
system
* 3.3.3 (set by ${PYENV_TEST_DIR}/.python-version)
3.4.0
OUT
}
@test "ignores non-directories under versions" {
create_version "3.3"
touch "${PYENV_ROOT}/versions/hello"
run pyenv-versions --bare
assert_success "3.3"
}
@test "lists symlinks under versions" {
create_version "2.7.8"
create_alias "2.7" "2.7.8"
run pyenv-versions --bare
assert_success
assert_output <<OUT
2.7
2.7.8
OUT
}
@test "doesn't list symlink aliases when --skip-aliases" {
create_version "1.8.7"
create_alias "1.8" "1.8.7"
create_external_version "moo"
run pyenv-versions --bare --skip-aliases
assert_success
assert_output <<OUT
1.8.7
moo
OUT
}
@test "--executables lists executables everywhere and overrides other switches" {
create_alt_executable_in_version "3.5.0" "python"
create_alt_executable_in_version "3.5.0" "python1"
create_alt_executable_in_version "3.6.0" "python"
create_alt_executable_in_version "3.5.0/envs/foo" "python_foo"
create_alt_executable_in_version "3.6.0/envs/bar" "python_bar"
create_alias "bar" "3.6.0/envs/bar"
create_external_version "moo"
create_alt_executable_in_version "moo" "moopython"
run pyenv-versions --skip-aliases --skip-envs --executables
assert_success
#The sort order does not matter for this functionality. However,
#MacOS 15 `sort` sorts differently that Linux's due to a different LC_COLLATE definition for en-US:
#https://unix.stackexchange.com/questions/362728/why-does-gnu-sort-sort-differently-on-my-osx-machine-and-linux-machine
#So to get a match, we have to check against the same order that the local `sort` produces
sort <<OUT | assert_output
moopython
python
python1
python_bar
python_foo
OUT
}
@test "lists dot directories under versions" {
create_version ".venv"
run pyenv-versions --bare
assert_success ".venv"
}
@test "sort supports version sorting" {
create_version "1.9.0"
create_version "1.53.0"
create_version "1.218.0"
create_path_executable sort <<SH
#!$BASH
cat >/dev/null
if [ "\$1" == "--version-sort" ]; then
echo "${PYENV_ROOT}/versions/1.9.0"
echo "${PYENV_ROOT}/versions/1.53.0"
echo "${PYENV_ROOT}/versions/1.218.0"
else exit 1
fi
SH
run pyenv-versions --bare
assert_success
assert_output <<OUT
1.9.0
1.53.0
1.218.0
OUT
}
@test "sort doesn't support version sorting" {
create_version "1.9.0"
create_version "1.53.0"
create_version "1.218.0"
create_path_executable sort <<SH
#!$BASH
exit 1
SH
run pyenv-versions --bare
assert_success
assert_output <<OUT
1.218.0
1.53.0
1.9.0
OUT
}
@test "non-bare output shows symlink contents" {
stub_system_python
create_version "1.9.0"
create_alias "link" "1.9.0"
run pyenv-versions
assert_success
assert_output <<OUT
* system (set by ${PYENV_ROOT}/version)
1.9.0
link --> 1.9.0
OUT
}

23
test/whence.bats Normal file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bats
load test_helper
@test "finds versions where present" {
create_alt_executable_in_version "2.7" "python"
create_alt_executable_in_version "2.7" "fab"
create_alt_executable_in_version "3.4" "python"
create_alt_executable_in_version "3.4" "py.test"
run pyenv-whence python
assert_success
assert_output <<OUT
2.7
3.4
OUT
run pyenv-whence fab
assert_success "2.7"
run pyenv-whence py.test
assert_success "3.4"
}

221
test/which.bats Normal file
View File

@@ -0,0 +1,221 @@
#!/usr/bin/env bats
load test_helper
@test "outputs path to executable" {
create_alt_executable_in_version "2.7" "python"
create_alt_executable_in_version "3.4" "py.test"
PYENV_VERSION=2.7 run pyenv-which python
assert_success "${PYENV_ROOT}/versions/2.7/bin/python"
PYENV_VERSION=3.4 run pyenv-which py.test
assert_success "${PYENV_ROOT}/versions/3.4/bin/py.test"
PYENV_VERSION=3.4:2.7 run pyenv-which py.test
assert_success "${PYENV_ROOT}/versions/3.4/bin/py.test"
}
@test "searches PATH for system version" {
create_path_executable "kill-all-humans"
create_executable "${PYENV_ROOT}/shims" "kill-all-humans"
PYENV_VERSION=system run pyenv-which kill-all-humans
assert_success "${PYENV_TEST_DIR}/bin/kill-all-humans"
}
@test "searches PATH for system version (shims prepended)" {
create_path_executable "kill-all-humans"
create_executable "${PYENV_ROOT}/shims" "kill-all-humans"
PATH="${PYENV_ROOT}/shims:$PATH" PYENV_VERSION=system run pyenv-which kill-all-humans
assert_success "${PYENV_TEST_DIR}/bin/kill-all-humans"
}
@test "searches PATH for system version (shims appended)" {
create_path_executable "kill-all-humans"
create_executable "${PYENV_ROOT}/shims" "kill-all-humans"
PATH="$PATH:${PYENV_ROOT}/shims" PYENV_VERSION=system run pyenv-which kill-all-humans
assert_success "${PYENV_TEST_DIR}/bin/kill-all-humans"
}
@test "searches PATH for system version (shims spread)" {
create_path_executable "kill-all-humans"
create_executable "${PYENV_ROOT}/shims" "kill-all-humans"
PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/shims:/tmp/non-existent:$PATH:${PYENV_ROOT}/shims" \
PYENV_VERSION=system run pyenv-which kill-all-humans
assert_success "${PYENV_TEST_DIR}/bin/kill-all-humans"
}
@test "doesn't include current directory in PATH search" {
bats_require_minimum_version 1.5.0
create_executable "$PYENV_TEST_DIR" kill-all-humans
cd "$PYENV_TEST_DIR"
PATH="$(path_without "kill-all-humans")" PYENV_VERSION=system run -127 pyenv-which kill-all-humans
assert_failure "pyenv: kill-all-humans: command not found"
}
@test "version not installed" {
bats_require_minimum_version 1.5.0
create_alt_executable_in_version "3.4" "py.test"
PYENV_VERSION=3.3 run -127 pyenv-which py.test
assert_failure <<OUT
pyenv: version \`3.3' is not installed (set by PYENV_VERSION environment variable)
pyenv: py.test: command not found
The \`py.test' command exists in these Python versions:
3.4
Note: See 'pyenv help global' for tips on allowing multiple
Python versions to be found at the same time.
OUT
}
@test "versions not installed" {
bats_require_minimum_version 1.5.0
create_alt_executable_in_version "3.4" "py.test"
PYENV_VERSION=2.7:3.3 run -127 pyenv-which py.test
assert_failure <<OUT
pyenv: version \`2.7' is not installed (set by PYENV_VERSION environment variable)
pyenv: version \`3.3' is not installed (set by PYENV_VERSION environment variable)
pyenv: py.test: command not found
The \`py.test' command exists in these Python versions:
3.4
Note: See 'pyenv help global' for tips on allowing multiple
Python versions to be found at the same time.
OUT
}
@test "no executable found" {
bats_require_minimum_version 1.5.0
create_alt_executable_in_version "2.7" "py.test"
PYENV_VERSION=2.7 run -127 pyenv-which fab
assert_failure "pyenv: fab: command not found"
}
@test "no executable found for system version" {
bats_require_minimum_version 1.5.0
PATH="$(path_without "rake")" PYENV_VERSION=system run -127 pyenv-which rake
assert_failure "pyenv: rake: command not found"
}
@test "executable found in other versions" {
bats_require_minimum_version 1.5.0
create_alt_executable_in_version "2.7" "python"
create_alt_executable_in_version "3.3" "py.test"
create_alt_executable_in_version "3.4" "py.test"
PYENV_VERSION=2.7 run -127 pyenv-which py.test
assert_failure
assert_output <<OUT
pyenv: py.test: command not found
The \`py.test' command exists in these Python versions:
3.3
3.4
Note: See 'pyenv help global' for tips on allowing multiple
Python versions to be found at the same time.
OUT
}
@test "carries original IFS within hooks" {
create_hook which hello.bash <<SH
hellos=(\$(printf "hello\\tugly world\\nagain"))
echo HELLO="\$(printf ":%s" "\${hellos[@]}")"
exit
SH
IFS=$' \t\n' PYENV_VERSION=system run pyenv-which anything
assert_success
assert_output "HELLO=:hello:ugly:world:again"
}
@test "discovers version from pyenv-version-name" {
mkdir -p "$PYENV_ROOT"
cat > "${PYENV_ROOT}/version" <<<"3.4"
create_alt_executable_in_version "3.4" "python"
mkdir -p "$PYENV_TEST_DIR"
cd "$PYENV_TEST_DIR"
PYENV_VERSION= run pyenv-which python
assert_success "${PYENV_ROOT}/versions/3.4/bin/python"
}
@test "tolerates nonexistent versions from pyenv-version-name" {
mkdir -p "$PYENV_ROOT"
cat > "${PYENV_ROOT}/version" <<EOF
2.7
3.4
EOF
create_alt_executable_in_version "3.4" "python"
mkdir -p "$PYENV_TEST_DIR"
cd "$PYENV_TEST_DIR"
PYENV_VERSION= run pyenv-which python
assert_success "${PYENV_ROOT}/versions/3.4/bin/python"
}
@test "resolves pyenv-latest prefixes" {
create_alt_executable_in_version "3.4.2" "python"
PYENV_VERSION=3.4 run pyenv-which python
assert_success "${PYENV_ROOT}/versions/3.4.2/bin/python"
}
@test "hooks get resolved version name" {
create_hook which echo.bash <<!
echo version=\$version
exit
!
create_alt_executable_in_version "3.4.2" "python"
PYENV_VERSION=3.4 run pyenv-which python
assert_success "version=3.4.2"
}
@test "skip advice supresses error messages" {
bats_require_minimum_version 1.5.0
create_alt_executable_in_version "2.7" "python"
create_alt_executable_in_version "3.3" "py.test"
create_alt_executable_in_version "3.4" "py.test"
PYENV_VERSION=2.7 run -127 pyenv-which py.test --skip-advice
assert_failure
assert_output <<OUT
pyenv: py.test: command not found
OUT
}
@test "excludes paths in _PYENV_SHIM_PATHS_{PROGRAM} from search only for PROGRAM" {
progname='123;wacky-prog.name ^%$#'
envvarname="_PYENV_SHIM_PATHS_123_WACKY_PROG_NAME_____"
create_path_executable "$progname"
for dir_ in "$BATS_TEST_TMPDIR/alt-path"{1,2}; do
mkdir -p "$dir_"
ln -s "${PYENV_TEST_DIR}/bin/$progname" "$dir_/$progname"
eval 'export '"$envvarname"'="$dir_${'"$envvarname"':+:$'"$envvarname"'}"'
PATH="$dir_:$PATH"
done
create_executable "$dir_" "normal_program"
run pyenv-which "$progname"
assert_success
assert_output <<!
$PYENV_TEST_DIR/bin/$progname
!
run pyenv-which "normal_program"
assert_success
assert_output <<!
$dir_/normal_program
!
}