realpath/test.sh

267 lines
6.3 KiB
Bash
Executable file

#!/bin/sh
set -eu
# we use the full path to realpath so that the coreutils version of realpath is
# used even when run with busybox in $PATH
realpath_m() {
REPLY=$(/usr/bin/realpath -m "$1")
}
realpath_m2() {
REPLY=$("$origpwd/realpath_m.sh" "$1")
}
assert() {
expected=$1
shift
if "$@" && [ "$REPLY" = "$expected" ]; then
numok=$((numok+1))
else
numfail=$((numfail+1))
echo "$@: expected '$expected', got '$REPLY'"
fi
}
compare() {
cmd=$1
shift
assert "$("$cmd" "$@")" realpath_"$cmd" "$@"
}
origpwd=$(pwd)
numokay=0
numfail=0
# realpath_dirname and realpath_basename should produce the same results as their operating system counterparts.
. "./realpath.sh"
for p1 in '' / // . ..; do
for p2 in '' /; do
for p3 in foo . ..; do
for p4 in '' /bar /. /..; do
for p5 in '' / // /// /. /..; do
compare basename "$p1$p2$p3$p4$p5"
compare dirname "$p1$p2$p3$p4$p5"
done
done
done
done
done
## realpath_absolute
# Outputs PWD with no args, joins relative args to PWD, removes empty parts, and
# canonicalizes ./..:
assert "$PWD" realpath_absolute
assert "$PWD" realpath_absolute .
assert "$PWD/x" realpath_absolute x
assert "$PWD/x/y" realpath_absolute x y
assert "$PWD/x/y" realpath_absolute x/z ../y
assert "$PWD/x/y/z" realpath_absolute x y//z
assert "$PWD/x/y/z" realpath_absolute x y '' z
assert "$PWD/x/y/z" realpath_absolute x y '' z/.
assert "$PWD/x/y/z" realpath_absolute x y '' z/. q .. r .. .. z
# Ignores arguments to the left of an absolute path:
assert /etc realpath_absolute /etc
assert /etc/z/xq realpath_absolute x y z /etc/z q/../xq
# Preserves double (but not triple+) slashes at the beginning of an absolute
# path:
assert //server/share/blah realpath_absolute //server share blah/
assert /server/share/blah realpath_absolute ///server/share blah
assert /server/share/blah realpath_absolute ////server/share blah
## realpath_relative path dir
# Outputs the relative path from dir to path:
assert y realpath_relative y .
assert y realpath_relative x/y x
assert ../y realpath_relative y x
assert ../y/z realpath_relative a/y/z a/x
assert ../../y realpath_relative y a/x
assert ../../../y realpath_relative y a/b/x
# Avoids redundancy for common path elements:
assert . realpath_relative y y
assert .. realpath_relative y y/x
assert ../.. realpath_relative y y/z/x
assert ../../.. realpath_relative /y /y/z/x/a
# Produces the same outputs as python's os.path.relpath:
relative() { /usr/bin/python3 -c 'import sys,os.path; sys.stdout.write(os.path.relpath(*sys.argv[1:3]))' "$@"; }
compare relative /q /q/r/s
compare relative /q/r /q/r/s
compare relative /q/r/s /q/r/s
compare relative /q/r/s/t /q/r/s
compare relative /q/r/s/t/u /q/r/s
compare relative /q/r/t /q/r/s
compare relative /q/r/t/u /q/r/s
compare relative /q/t /q/r/s
compare relative /q/t/u /q/r/s
compare relative /t/u/v /q/r/s
## realpath_follow
# Returns first non-symlink:
assert "x" realpath_follow x
ln -s y x
assert "y" realpath_follow x
ln -s z y
assert "z" realpath_follow x
# or last symlink before recursion sets in:
ln -s x z
assert "z" realpath_follow x
assert "y" realpath_follow z
assert "x" realpath_follow y
# and relative-pathed symlinks are normalized to the symlink directory
mkdir q
assert "q/../z" realpath_follow q/../x
rm x y z; rmdir q
## realpath_canonical
# Current directory:
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD" "$cmd" .
assert "$PWD" "$cmd" "$PWD"
done
# Nonexistent file:
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD/x" "$cmd" x
assert "$PWD/x" "$cmd" "$PWD/x"
done
# Symlink to non-existent target:
ln -s y x
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD/y" "$cmd" x
assert "$PWD/y" "$cmd" "$PWD/x"
done
# Symlink chain:
ln -s z y
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD/z" "$cmd" x
assert "$PWD/z" "$cmd" "$PWD/x"
done
# Symlink loop breaks on the looper:
ln -s y z
# difference to realpath -m: returned path is the target
assert "$PWD/z" realpath_canonical x
assert "$PWD/y" realpath_m x
assert "$PWD/z" realpath_m2 x
rm x y z
# Absolute links and directories:
touch y
mkdir z
ln -s $PWD/y x
ln -s $PWD/x z/x
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD/y" "$cmd" x
assert "$PWD/y" "$cmd" z/x
done
ln -sf ../x z/x
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD/y" "$cmd" x
assert "$PWD/y" "$cmd" z/x
done
ln -s z q
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD/z" "$cmd" q
assert "$PWD/y" "$cmd" q/../x
assert "$PWD/z/a" "$cmd" q/a
done
## realpath_location
# Returns the absolute (but not canonical) location of the directory physically
# containing its target. Is equivalent to `realpath_absolute` if target isn't
# a symlink:
assert "$PWD" realpath_location x
assert "$PWD" realpath_location z
assert "$PWD/z" realpath_location z/a
assert "$PWD" realpath_location q/x # -> ../x
assert "$PWD/q" realpath_location q/foo
assert "$PWD" realpath_location q/../foo
assert "$PWD/q/foo" realpath_location q/foo/bar
### Missing elements
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$PWD/z/foo/bar/baz" "$cmd" q/foo/bar/baz
assert "$PWD/z/foo/bar" "$cmd" q/foo/bar
assert /non-existent "$cmd" /non-existent
assert /etc/non-existent "$cmd" /etc/non-existent
done
### Subdirectories, accessible and inaccessible
# Works while the directory is accesible:
mkdir foo
cd foo
for cmd in realpath_canonical realpath_m realpath_m2; do
assert "$OLDPWD/z" "$cmd" "$OLDPWD/q"
assert "$OLDPWD/y" "$cmd" "$OLDPWD/q/x"
assert "$OLDPWD/y" "$cmd" "../q/x"
done
# realpath -m cannot operate on inaccessible $PWD
# We can follow symlinks even if $PWD is inaccessible:
rmdir ../foo
for cmd in realpath_canonical; do
assert "$OLDPWD/z" "$cmd" "$OLDPWD/q"
assert "$OLDPWD/y" "$cmd" "../q/x"
done
# And we can do non-symlink canonicalizing on the base dir of the results:
for cmd in realpath_canonical; do
assert "$OLDPWD/z" "$cmd" "../z"
assert "$OLDPWD/z/foo" "$cmd" "../z/foo"
assert "$OLDPWD/foo" "$cmd" "../foo"
assert "$OLDPWD/z" "$cmd" "../q"
done
cd ..
rm x y q z/x
rmdir z
echo "number of successes: $numok"
echo "number of failures: $numfail"
if [ "$numfail" -gt 0 ]; then
exit 1
fi