From 18be2ea720d91e6feee33e848eb1d6ceb9217122 Mon Sep 17 00:00:00 2001 From: smoon Date: Wed, 11 May 2016 17:19:18 +0900 Subject: [PATCH 1/3] emulate readlink using posix ls --- realpath.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/realpath.sh b/realpath.sh index 716a601..b3ea55b 100644 --- a/realpath.sh +++ b/realpath.sh @@ -93,7 +93,7 @@ _emulated_readlink() { shift fi - _gnu_stat_readlink "$@" || _bsd_stat_readlink "$@" + _posix_ls_readlink "$@" || _gnu_stat_readlink "$@" || _bsd_stat_readlink "$@" } _gnu_stat_readlink() { @@ -109,3 +109,7 @@ _gnu_stat_readlink() { _bsd_stat_readlink() { stat -f %Y -- "$1" 2>/dev/null } + +_posix_ls_readlink() { + LC_TIME=POSIX ls -l -- "$1" | sed -e 's/^.\{11\}\ *[0-9]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[0-9]\{1,\}\ *[^ ]*\ *[0-9]\{1,2\}\ *[^\ ]*\ \(.*\)/\1/g' -e 's/.* -> //g' 2>/dev/null +} From 203b823484279f7ccb80e6d1308237a34056ab62 Mon Sep 17 00:00:00 2001 From: smoon Date: Fri, 13 May 2016 14:02:30 +0900 Subject: [PATCH 2/3] remove g flag in regex ls(1) stderr redirect to /dev/null --- realpath.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/realpath.sh b/realpath.sh index b3ea55b..6f53b1a 100644 --- a/realpath.sh +++ b/realpath.sh @@ -111,5 +111,5 @@ _bsd_stat_readlink() { } _posix_ls_readlink() { - LC_TIME=POSIX ls -l -- "$1" | sed -e 's/^.\{11\}\ *[0-9]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[0-9]\{1,\}\ *[^ ]*\ *[0-9]\{1,2\}\ *[^\ ]*\ \(.*\)/\1/g' -e 's/.* -> //g' 2>/dev/null + LC_TIME=POSIX ls -l -- "$1" 2>/dev/null | sed -e 's/^.\{11\}\ *[0-9]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[0-9]\{1,\}\ *[^ ]*\ *[0-9]\{1,2\}\ *[^\ ]*\ \(.*\)/\1/' -e 's/.* -> //g' 2>/dev/null } From 8222b0a2c2e611d8e79277cfb58795a1333dcdf5 Mon Sep 17 00:00:00 2001 From: smoon Date: Sat, 14 May 2016 02:09:12 +0900 Subject: [PATCH 3/3] added posix_ls_readlink emulation automated test bugfix posix_ls_readlink --- realpath.sh | 4 +- t/test_posix_ls_readlink_emulation | 360 +++++++++++++++++++++++++++++ 2 files changed, 363 insertions(+), 1 deletion(-) create mode 100755 t/test_posix_ls_readlink_emulation diff --git a/realpath.sh b/realpath.sh index 6f53b1a..de69f10 100644 --- a/realpath.sh +++ b/realpath.sh @@ -111,5 +111,7 @@ _bsd_stat_readlink() { } _posix_ls_readlink() { - LC_TIME=POSIX ls -l -- "$1" 2>/dev/null | sed -e 's/^.\{11\}\ *[0-9]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[0-9]\{1,\}\ *[^ ]*\ *[0-9]\{1,2\}\ *[^\ ]*\ \(.*\)/\1/' -e 's/.* -> //g' 2>/dev/null + name=$1 + escaped_name=$(printf "%s" "$name" | sed -e 's/\\/\\\\/g' -e 's/\[/\\[/g' -e 's/\*/\\*/g' -e 's/\^/\\^/g') + LC_TIME=POSIX ls -l -- "$name" 2>/dev/null | sed -e 's/^.\{11\}\ *[0-9]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[a-zA-Z\._@\$-]\{1,\}\ *[0-9]\{1,\}\ *[^ ]*\ *[0-9]\{1,2\}\ *[^\ ]*\ \(.*\)/\1/' -e "s/$escaped_name -> //" 2>/dev/null } diff --git a/t/test_posix_ls_readlink_emulation b/t/test_posix_ls_readlink_emulation new file mode 100755 index 0000000..90fd7f7 --- /dev/null +++ b/t/test_posix_ls_readlink_emulation @@ -0,0 +1,360 @@ +#!/bin/sh + +setUp() { + . ./realpath.sh + + _has_command() { + return 1 + } + + current_path=$(pwd) + mkdir _posix_ls_readlink_test_directory +} + +tearDown() { + cd $current_path + rm -rf _posix_ls_readlink_test_directory +} + +it_calls_system_readlink_when_has_command_readlink_is_true() { + _has_command() { + test "$1" = readlink + } + + local readlink_arg1 readlink_arg2 + _system_readlink() { + readlink_arg1="$1" + readlink_arg2="$2" + } + + readlink -- some/path + + assertEquals -- "$readlink_arg1" + assertEquals some/path "$readlink_arg2" +} + +it_calls__posix_ls_readlink_when_has_command_readlink_is_false() { + local called + _posix_ls_readlink() { + called=1 + } + + readlink -- some/path + + assertNotNull "_posix_ls_readlink called" "$called" +} + +it_passes_actual_arg_to__posix_ls_readlink() { + local arg + _posix_ls_readlink() { + arg="$1" + } + + readlink -- some/path + + assertEquals some/path "$arg" +} + +it_passes_first_arg_to__posix_ls_readlink_when_no_dashes() { + local arg + _posix_ls_readlink() { + arg="$1" + } + + readlink some/path + + assertEquals some/path "$arg" +} + +it_doesnt_call_stat_readlink_when__posix_readlink_returns_true() { + _posix_ls_readlink() { + return 0 + } + + local called + _bsd_stat_readlink() { + called=1 + } + + _gnu_stat_readlink() { + called=1 + } + + readlink -- some/path + + assertNull "_bsd_stat_readlink not called" "$called" +} + +it_ok_normal_symbolic_link() { + local output + + cd _posix_ls_readlink_test_directory + + touch target_file + ln -s target_file file_symbolic_link + + output=$(readlink file_symbolic_link) + + assertEquals "target_file" $output + + mkdir target_dir + ln -s target_dir dir_symbolic_link + + output=$(readlink dir_symbolic_link) + + assertEquals "target_dir" $output +} + +it_ok_normal_symbolic_link_to_directory_with_trailing_slash() { + local output + + cd _posix_ls_readlink_test_directory + + mkdir target + ln -s target/ symbolic_link + + output=$(readlink symbolic_link) + + assertEquals "target/" $output +} + +it_ok_symbolic_link_name_has_space() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target "symbolic link" + + output=$(readlink "symbolic link") + + assertEquals "target" $output +} + +it_ok_symbolic_link_name_first_character_is_space() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target " symbolic link" + + output=$(readlink " symbolic link") + + assertEquals "target" $output +} + +it_ok_symbolic_link_name_last_character_is_space() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target " symbolic link " + + output=$(readlink " symbolic link ") + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_with_BRE_metachar_dot_asterisk() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target ' symbolic link .*' + + output=$(readlink ' symbolic link .*') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_with_BRE_metachar_anchor() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target ' symbolic ^link ' + + output=$(readlink ' symbolic ^link ') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_BRE_metachar_anchor_only() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target '^' + + output=$(readlink '^') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_with_BRE_metachar_dollar() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target 'symbolic $' + + output=$(readlink 'symbolic $') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_BRE_metachar_dollar_only() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s target '$' + + output=$(readlink '$') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_start_with_hypen() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s -- target '-n symbolic' + + output=$(readlink '-n symbolic') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_start_with_hypen() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s -- target '-n symbolic' + + output=$(readlink '-n symbolic') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_with_bracket() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s -- target '-n symbolic [a-z]' + + output=$(readlink '-n symbolic [a-z]') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_with_bracket() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s -- target '-n symbolic [a-z]' + + output=$(readlink '-n symbolic [a-z]') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_with_back_slash() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s -- target '-n \symbolic [a-z]' + + output=$(readlink '-n \symbolic [a-z]') + + assertEquals "target" "$output" +} + +it_ok_symbolic_link_name_with_posix_ls_symbolic_link_mark() { + local output + + cd _posix_ls_readlink_test_directory + + touch target + ln -s -- target '-n \symbolic [a-z] -> link' + + output=$(readlink '-n \symbolic [a-z] -> link') + + assertEquals "target" "$output" +} + +it_ok_target_name_with_posix_ls_symbolic_link_mark() { + local output + + cd _posix_ls_readlink_test_directory + + touch 'target -> file -> name' + ln -s -- 'target -> file -> name' '-n \symbolic [a-z] -> link' + + output=$(readlink '-n \symbolic [a-z] -> link') + + assertEquals 'target -> file -> name' "$output" +} + +it_ok_target_name_start_with_space() { + local output + + cd _posix_ls_readlink_test_directory + + touch ' target -> file -> name' + ln -s -- ' target -> file -> name' '-n \symbolic [a-z] -> link' + + output=$(readlink '-n \symbolic [a-z] -> link') + + assertEquals ' target -> file -> name' "$output" +} + +it_ok_target_name_with_trailing_space() { + local output + + cd _posix_ls_readlink_test_directory + + touch ' target -> file -> name ' + ln -s -- ' target -> file -> name ' '-n \symbolic [a-z] -> link' + + output=$(readlink '-n \symbolic [a-z] -> link') + + assertEquals ' target -> file -> name ' "$output" +} + +##### Test Harness ##### + +# suite() -- find and register tests to be run +# Derived from Gary Bernhardt's screencast #68 +# (https://www.destroyallsoftware.com/screencasts/catalog/test-driving-shell-scripts) +suite() { + local name tests + tests=$(grep ^it_ "$0" | cut -d '(' -f 1) + for name in $tests; do + suite_addTest "$name" + done +} + +if hash shunit2 2>/dev/null; then + . shunit2 +else + echo 'Error: shunit2(1) could not be located. Please install it on your $PATH.' >&2 + exit 1 +fi