292 lines
8.5 KiB
YAML
292 lines
8.5 KiB
YAML
name: "PATH search"
|
|
|
|
#
|
|
# An empty entry in PATH names the working directory, so a command found through one is
|
|
# reported with a leading "./". brush finds the command but reports the bare name; the
|
|
# `known_failure` cases below cover each surface that exposes the difference. They share
|
|
# one root cause in the path search, so they should be retired together.
|
|
#
|
|
cases:
|
|
- name: "empty PATH entry is reported as the working directory"
|
|
known_failure: true # TODO(path): an empty PATH entry should resolve as "."
|
|
stdin: |
|
|
printf '#!/bin/sh\necho ran\n' > prog
|
|
chmod +x prog
|
|
PATH=":$PATH"
|
|
|
|
echo "[type]"
|
|
type prog; echo "rc=$?"
|
|
echo "[type -p]"
|
|
type -p prog; echo "rc=$?"
|
|
echo "[type -P]"
|
|
type -P prog; echo "rc=$?"
|
|
echo "[type -a]"
|
|
type -a prog; echo "rc=$?"
|
|
echo "[command -v]"
|
|
command -v prog; echo "rc=$?"
|
|
|
|
- name: "empty PATH entry is reported the same wherever it appears"
|
|
known_failure: true # TODO(path): an empty PATH entry should resolve as "."
|
|
stdin: |
|
|
printf '#!/bin/sh\necho ran\n' > prog
|
|
chmod +x prog
|
|
original=$PATH
|
|
|
|
# Each of these keeps the rest of PATH reachable, so only the empty entry can
|
|
# account for finding `prog`, which exists solely in the working directory.
|
|
echo "[leading]"
|
|
PATH=":$original"; hash -r
|
|
command -v prog; echo "rc=$?"
|
|
|
|
echo "[trailing]"
|
|
PATH="$original:"; hash -r
|
|
command -v prog; echo "rc=$?"
|
|
|
|
echo "[middle]"
|
|
PATH="/nonexistent::$original"; hash -r
|
|
command -v prog; echo "rc=$?"
|
|
|
|
- name: "empty PATH entry is hashed as the working directory"
|
|
known_failure: true # TODO(path): an empty PATH entry should resolve as "."
|
|
stdin: |
|
|
printf '#!/bin/sh\necho ran\n' > prog
|
|
chmod +x prog
|
|
PATH=":$PATH"
|
|
|
|
hash -r
|
|
hash prog; echo "rc=$?"
|
|
hash -t prog; echo "rc=$?"
|
|
|
|
- name: "empty PATH entry is passed to the command as the working directory"
|
|
known_failure: true # TODO(path): an empty PATH entry should resolve as "."
|
|
stdin: |
|
|
# A copy of env, found through the empty entry before the real one, reports the _
|
|
# it's started with: the path the shell ran it by. (It keeps env's name, which a
|
|
# multi-call binary such as NixOS's coreutils goes by.)
|
|
cp "$(command -v env)" env
|
|
PATH=":$PATH"
|
|
|
|
env | grep '^_='
|
|
|
|
- name: "relative PATH entry is relative to the working directory"
|
|
known_failure: true # TODO(path): a relative PATH entry is searched relative to the directory brush started in, not the shell's working directory
|
|
test_files:
|
|
- path: "sub/bin/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "ran prog"
|
|
stdin: |
|
|
cd sub
|
|
PATH=bin
|
|
type prog
|
|
type -a prog
|
|
command -v prog
|
|
hash prog; echo "hash: $?"
|
|
prog; echo "command: $?"
|
|
(exec prog); echo "exec in a subshell: $?"
|
|
exec prog
|
|
|
|
- name: "script run by a relative path sees that path as its $0"
|
|
known_failure: true # TODO(path): a relative PATH entry is searched relative to the directory brush started in, not the shell's working directory
|
|
test_files:
|
|
- path: "sub/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "0=$0"
|
|
- path: "sub/bin/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "0=$0"
|
|
stdin: |
|
|
cd sub
|
|
./prog
|
|
PATH=bin
|
|
prog
|
|
|
|
- name: "empty PATH entry runs the program in the working directory"
|
|
known_failure: true # TODO(path): an empty PATH entry should resolve as "."
|
|
test_files:
|
|
- path: "sub/id"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "id in the working directory"
|
|
- path: "sub/only-here"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "only here"
|
|
stdin: |
|
|
# Unexported, so that the program can't be found again through the PATH a
|
|
# process is given, only as the shell found it.
|
|
cd sub
|
|
export -n PATH
|
|
PATH=":$PATH"
|
|
id
|
|
only-here
|
|
type only-here
|
|
|
|
- name: "command found through an empty PATH entry is searched for again after cd"
|
|
known_failure: true # TODO(hash): a command hashed as found in the working directory isn't searched for again after cd
|
|
test_files:
|
|
- path: "a/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "prog in a"
|
|
- path: "b/.keep"
|
|
- path: "fallback/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "prog in fallback"
|
|
stdin: |
|
|
for first in "" "."; do
|
|
export PATH="${first}:${PWD}/fallback:${PATH}"
|
|
cd a
|
|
prog
|
|
hash -t prog; type prog
|
|
cd ../b
|
|
prog; echo "status: $?"
|
|
cd ../a
|
|
prog
|
|
hash -t prog; type prog
|
|
cd ..
|
|
export PATH="${PATH#"${first}:${PWD}/fallback:"}"
|
|
done
|
|
|
|
- name: "PATH entry for the working directory written another way"
|
|
known_failure: true # TODO(path): a PATH entry such as `./` or `../dir` isn't taken to be the working directory
|
|
test_files:
|
|
- path: "a/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "prog in a"
|
|
- path: "b/.keep"
|
|
- path: "fallback/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "prog in fallback"
|
|
stdin: |
|
|
fallback="${PWD}/fallback"
|
|
for first in ./ ./. .// ../b; do
|
|
PATH="${first}:${fallback}"
|
|
hash -r
|
|
cd b
|
|
prog
|
|
cd ../a
|
|
prog
|
|
hash -t prog
|
|
cd ..
|
|
done
|
|
|
|
- name: "command found through a PATH entry is run by the path that entry gives it"
|
|
test_files:
|
|
- path: "bin/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "0=$0"
|
|
stdin: |
|
|
PATH=./bin//
|
|
prog
|
|
PATH=.//bin
|
|
hash -r
|
|
prog
|
|
|
|
- name: "PATH entry starting with a dot is the working directory only if it's the same"
|
|
known_failure: true # TODO(path): a PATH entry that's the working directory under another name isn't taken to be it
|
|
test_files:
|
|
- path: "a/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "prog in a"
|
|
- path: "b/sub/.keep"
|
|
- path: "b/.hidden/.keep"
|
|
- path: "fallback/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "prog in fallback"
|
|
stdin: |
|
|
fallback="${PWD}/fallback"
|
|
ln -s . b/self
|
|
for first in ./sub .hidden .nosuch ./self; do
|
|
echo "[${first}]"
|
|
PATH="${first}:${fallback}"
|
|
hash -r
|
|
cd b
|
|
prog
|
|
cd ../a
|
|
prog
|
|
cd ..
|
|
done
|
|
|
|
- name: "command hashed with hash -p is kept with an empty PATH entry"
|
|
test_files:
|
|
- path: "prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "prog in the working directory"
|
|
stdin: |
|
|
true_path=$(type -P true)
|
|
PATH=":$PATH"
|
|
hash -p "${true_path}" prog
|
|
prog; echo "status: $?"
|
|
|
|
- name: "with PATH unset, a command in the working directory is run by its name"
|
|
known_failure: true # TODO(path): with PATH unset, a command in the working directory is run as ./name, not by its bare name
|
|
test_files:
|
|
- path: "prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "0=$0"
|
|
stdin: |
|
|
unset PATH
|
|
prog
|
|
|
|
- name: "relative PATH entry is hashed as bash hashes it"
|
|
known_failure: true # TODO(hash): bash hashes a command found through a relative PATH entry as ./entry/name
|
|
test_files:
|
|
- path: "sub/bin/prog"
|
|
executable: true
|
|
contents: |
|
|
#!/bin/sh
|
|
echo "ran prog"
|
|
stdin: |
|
|
cd sub
|
|
PATH=bin
|
|
prog
|
|
hash -t prog
|
|
|
|
#
|
|
# These two surfaces already agree with the oracle; they guard the parts of the
|
|
# behavior that work, so that a fix for the cases above doesn't regress them.
|
|
#
|
|
- name: "a command found through an empty PATH entry is runnable"
|
|
stdin: |
|
|
printf '#!/bin/sh\necho ran\n' > prog
|
|
chmod +x prog
|
|
PATH=":$PATH"
|
|
|
|
prog; echo "rc=$?"
|
|
|
|
- name: "command -V absolutizes a command found through an empty PATH entry"
|
|
stdin: |
|
|
# Normalize away the temporary directory the test runs in.
|
|
scrub() { sed -E "s|$PWD|<TMPDIR>|g"; }
|
|
|
|
printf '#!/bin/sh\necho ran\n' > prog
|
|
chmod +x prog
|
|
PATH=":$PATH"
|
|
|
|
command -V prog | scrub; echo "rc=${PIPESTATUS[0]}"
|