D7: editor multi-cursor support

Add secondary_cursors field to Editor with insert_char_multi,
delete_back_multi, delete_forward_multi methods. Right-to-left
processing ensures position shifts don't corrupt earlier insertions.

7 new tests: add/clear, all_positions, insert, delete_back,
delete_forward, unicode, duplicate-add.
This commit is contained in:
2026-07-05 22:29:19 +03:00
parent 7a2b0d5160
commit b8aac3c9bc
2226 changed files with 876572 additions and 2382 deletions
@@ -0,0 +1,92 @@
# tests for GNU diff
TESTS = \
basic \
bignum \
binary \
brief-vs-stat-zero-kernel-lies \
cmp \
colliding-file-names \
diff3 \
excess-slash \
help-version \
invalid-re \
function-line-vs-leading-space \
ignore-matching-lines \
label-vs-func \
new-file \
no-dereference \
no-newline-at-eof \
stdin \
strcoll-0-names \
filename-quoting \
colors
EXTRA_DIST = \
$(TESTS) init.sh t-local.sh envvar-check
# Note that the first lines are statements. They ensure that environment
# variables that can perturb tests are unset or set to expected values.
# The rest are envvar settings that propagate build-related Makefile
# variables to test scripts.
TESTS_ENVIRONMENT = \
tmp__=$${TMPDIR-/tmp}; \
test -d "$$tmp__" && test -w "$$tmp__" || tmp__=.; \
. $(srcdir)/envvar-check; \
TMPDIR=$$tmp__; export TMPDIR; \
\
if test -n "$$BASH_VERSION" || (eval "export v=x") 2>/dev/null; then \
export_with_values () { export "$$@"; }; \
else \
export_with_values () \
{ \
sed_extract_var='s/=.*//'; \
sed_quote_value="s/'/'\\\\''/g;s/=\\(.*\\)/='\\1'/";\
for arg in "$$@"; do \
var=`echo "$$arg" | sed "$$sed_extract_var"`; \
arg=`echo "$$arg" | sed "$$sed_quote_value"`; \
eval "$$arg"; \
export "$$var"; \
done; \
}; \
fi; \
\
export_with_values \
VERSION='$(VERSION)' \
LOCALE_FR='$(LOCALE_FR)' \
LOCALE_FR_UTF8='$(LOCALE_FR_UTF8)' \
AWK=$(AWK) \
GREP_OPTIONS='' \
LC_ALL=C \
abs_top_builddir='$(abs_top_builddir)' \
abs_top_srcdir='$(abs_top_srcdir)' \
abs_srcdir='$(abs_srcdir)' \
built_programs="`$(built_programs)`" \
srcdir='$(srcdir)' \
top_srcdir='$(top_srcdir)' \
CC='$(CC)' \
DIFFUTILS_TEST_NAME=`echo $$tst|sed 's,^\./,,;s,/,-,g'` \
MAKE=$(MAKE) \
MALLOC_PERTURB_=$(MALLOC_PERTURB_) \
PACKAGE_BUGREPORT='$(PACKAGE_BUGREPORT)' \
PACKAGE_VERSION=$(PACKAGE_VERSION) \
PERL='$(PERL)' \
SHELL='$(SHELL)' \
PREFERABLY_POSIX_SHELL='$(PREFERABLY_POSIX_SHELL)' \
REPLACE_GETCWD=$(REPLACE_GETCWD) \
PATH='$(abs_top_builddir)/src$(PATH_SEPARATOR)'"$$PATH" \
stderr_fileno_=9 \
; 9>&2
LOG_COMPILER= $(SHELL)
built_programs = \
echo 'spy:;@echo $$(PROGRAMS)' \
| { (cd ../src && MAKEFLAGS= $(MAKE) -s -f Makefile -f - spy) \
| tr ' ' '\n' \
| sed '/^$$/d; s,$(EXEEXT)$$,,' \
| sort -u \
| tr '\n' ' '; echo; } \
| sed 's/ $$//'
VERBOSE = yes
File diff suppressed because it is too large Load Diff
+42
View File
@@ -0,0 +1,42 @@
#!/bin/sh
# small examples
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
cat <<EOF > exp- || fail=1
1c1
< a
---
> b
EOF
cat <<EOF > exp--u || fail=1
--- a
+++ b
@@ -1 +1 @@
-a
+b
EOF
cat <<EOF > exp--c || fail=1
*** a
--- b
***************
*** 1 ****
! a
--- 1 ----
! b
EOF
echo a > a
echo b > b
for opt in '' -u -c; do
returns_ 1 diff $opt a b > out 2> err || fail=1
# Remove date and time.
sed -e 's/^\([-+*][-+*][-+*] [^ ]*\) .*/\1/' out > k; mv k out
compare exp-$(echo $opt|tr ' ' _) out || fail=1
done
Exit $fail
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
# big numbers
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
for tabsize in 2147483648 9223372036854775808; do
diff --tabsize=$tabsize /dev/null /dev/null
status=$?
test $status -eq 0 || test $status -eq 2 || fail=1
done
Exit $fail
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
# small examples
. "${srcdir=.}/init.sh"; path_prepend_ ../src
printf 'Binary files - and /dev/null differ\n' > out-exp || fail_ setup
fail=0
# diff must exit with status 1, stdout as above, and no stderr.
printf '\0'| returns_ 1 diff - /dev/null > out 2> err || fail=1
compare out-exp out || fail=1
compare /dev/null err || fail=1
Exit $fail
@@ -0,0 +1,38 @@
#!/bin/sh
# Before diff-3.4, diff --brief could mistakenly declare a difference.
# For example, when comparing a file like /proc/cmdline (for which the linux
# kernel reports a st_size of 0 even though it is not an empty file) to a
# copy of that file's contents residing on a "normal" file system.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
# Skip the test unless we have an appropriate file.
boot=/proc/cmdline
test -r $boot || skip_ no $boot file
sz=$(stat --format %s $boot) || skip_ stat --format %s does not work
test $sz = 0 || skip_ $boot has nonzero size
# /proc/self is not useful on the Hurd, where it always points to "1",
# so skip this test when /proc/self does not point to a file whose name is
# the current process ID.
readlink /proc/self > pid & pid=$!
wait $pid
echo $pid > exp
compare exp pid || skip_ /proc/self is not useful on this system
# There are two code paths to test: one for non-binary and one for binary files.
# $boot is non-binary.
cat $boot > ref || framework_failure_
diff --brief $boot ref > out 2>&1 || fail=1
compare /dev/null out || fail=1
# /proc/self/cmdline is a NUL-terminated list of argv values,
# so construct the expected output here:
printf 'diff\0--brief\0/proc/self/cmdline\0bin\0' > bin || framework_failure_
# And run the command that is embedded in that output:
diff --brief /proc/self/cmdline bin > out 2>&1 || fail=1
compare /dev/null out || fail=1
Exit $fail
+211
View File
@@ -0,0 +1,211 @@
#!/bin/sh
# Test 'cmp'.
# Copyright 2017 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
cat <<'EOF' > exp || fail=1
cmp a a
0
cmp a b
a b differ: char 1, line 1
1
cmp a c
cmp: EOF on c which is empty
1
cmp a d
cmp: d: No such file or directory
2
cmp b a
b a differ: char 1, line 1
1
cmp b b
0
cmp b c
cmp: EOF on c which is empty
1
cmp b d
cmp: d: No such file or directory
2
cmp c a
cmp: EOF on c which is empty
1
cmp c b
cmp: EOF on c which is empty
1
cmp c c
0
cmp c d
cmp: d: No such file or directory
2
cmp d a
cmp: d: No such file or directory
2
cmp d b
cmp: d: No such file or directory
2
cmp d c
cmp: d: No such file or directory
2
cmp d d
cmp: d: No such file or directory
2
cmp -l a a
0
cmp -l a b
1 141 142
1
cmp -l a c
cmp: EOF on c which is empty
1
cmp -l a d
cmp: d: No such file or directory
2
cmp -l b a
1 142 141
1
cmp -l b b
0
cmp -l b c
cmp: EOF on c which is empty
1
cmp -l b d
cmp: d: No such file or directory
2
cmp -l c a
cmp: EOF on c which is empty
1
cmp -l c b
cmp: EOF on c which is empty
1
cmp -l c c
0
cmp -l c d
cmp: d: No such file or directory
2
cmp -l d a
cmp: d: No such file or directory
2
cmp -l d b
cmp: d: No such file or directory
2
cmp -l d c
cmp: d: No such file or directory
2
cmp -l d d
cmp: d: No such file or directory
2
cmp -s a a
0
cmp -s a b
1
cmp -s a c
1
cmp -s a d
2
cmp -s b a
1
cmp -s b b
0
cmp -s b c
1
cmp -s b d
2
cmp -s c a
1
cmp -s c b
1
cmp -s c c
0
cmp -s c d
2
cmp -s d a
2
cmp -s d b
2
cmp -s d c
2
cmp -s d d
2
EOF
echo a >a
echo b >b
: >c
rm -f d
for option in '' -l -s; do
for i in a b c d; do
for j in a b c d; do
echo cmp $option $i $j
cmp $option $i $j >stdout 2>stderr
status=$?
cat stderr stdout
echo $status
done
done
done >out
compare exp out || fail=1
cat <<'EOF' > exp1 || fail=1
cmp a0 a1
cmp: EOF on a0 which is empty
1
cmp a1 a2
cmp: EOF on a1 after byte 2, line 1
1
cmp a2 a3
cmp: EOF on a2 after byte 5, in line 2
1
cmp -l a0 a1
cmp: EOF on a0 which is empty
1
cmp -l a1 a2
cmp: EOF on a1 after byte 2
1
cmp -l a2 a3
cmp: EOF on a2 after byte 5
1
cmp -s a0 a1
1
cmp -s a1 a2
1
cmp -s a2 a3
1
EOF
printf '' >a0
printf '1\n' >a1
printf '1\nfoo' >a2
printf '1\nfoolery\n' >a3
for option in '' -l -s; do
for files in 'a0 a1' 'a1 a2' 'a2 a3'; do
echo cmp $option $files
cmp $option $files >stdout 2>stderr
status=$?
cat stderr stdout
echo $status
done
done >out1
compare exp1 out1 || fail=1
Exit $fail
@@ -0,0 +1,19 @@
#!/bin/sh
# Check that diff responds well if a directory has multiple file names
# that compare equal.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
mkdir d1 d2 || fail=1
for i in abc abC aBc aBC; do
echo xyz >d1/$i || fail=1
done
for i in ABC ABc AbC Abc; do
echo xyz >d2/$i || fail=1
done
diff -r --ignore-file-name-case d1 d2 || fail=1
Exit $fail
+128
View File
@@ -0,0 +1,128 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ ../src
TZ=UTC0
export TZ
fail=0
echo a > a
echo b > b
epoch='1970-01-01 00:00:00'
touch -t 197001010000.00 a b
e=$(printf '\033')
tab=$(printf '\t')
gen_exp_u()
{
local epoch_plus="$epoch.000000000 +0000"
local rs=$(printf "$e[${rs}m")
local hd=$(printf "$e[${hd}m")
local ad=$(printf "$e[${ad}m")
local de=$(printf "$e[${de}m")
local ln=$(printf "$e[${ln}m")
printf '%s' \
"$hd--- a$tab$epoch_plus
+++ b$tab$epoch_plus
$rs${ln}@@ -1 +1 @@$rs
$de-a$rs
$ad+b$rs
"
}
gen_exp_c()
{
local epoch_posix_1003_1_2001="Thu Jan 1 00:00:00 1970"
local rs=$(printf "$e[${rs}m")
local hd=$(printf "$e[${hd}m")
local ad=$(printf "$e[${ad}m")
local de=$(printf "$e[${de}m")
local ln=$(printf "$e[${ln}m")
printf '%s' \
"$hd*** a$tab$epoch_posix_1003_1_2001
--- b$tab$epoch_posix_1003_1_2001
$rs***************
$ln*** 1 ****$rs
$de! a$rs
$ln--- 1 ----$rs
$ad! b$rs
"
}
gen_exp_default()
{
printf '%s' \
"1c1
< a
---
> b
"
}
gen_exp_default_colors()
{
local rs=$(printf "$e[${rs}m")
local hd=$(printf "$e[${hd}m")
local ad=$(printf "$e[${ad}m")
local de=$(printf "$e[${de}m")
local ln=$(printf "$e[${ln}m")
printf '%s' \
"${ln}1c1$rs
$de< a$rs
---
$ad> b$rs
"
}
# Compare with some known outputs
rs=0 hd=1 ad=32 de=31 ln=36
returns_ 1 diff --color=auto a b > out || fail=1
gen_exp_default > exp || framework_failure_
compare exp out || fail=1
returns_ 1 env TERM=dumb diff ---presume-output-tty --color=auto a b > out \
|| fail=1
gen_exp_default > exp || framework_failure_
compare exp out || fail=1
returns_ 1 diff --color=never a b > out || fail=1
gen_exp_default > exp || framework_failure_
compare exp out || fail=1
returns_ 1 diff a b > out || fail=1
gen_exp_default > exp || framework_failure_
compare exp out || fail=1
returns_ 1 diff --color=always a b > out || fail=1
gen_exp_default_colors > exp || framework_failure_
compare exp out || fail=1
returns_ 1 diff -u --color=always a b > out || fail=1
gen_exp_u > exp || framework_failure_
compare exp out || fail=1
returns_ 1 diff -c --color=always a b > out || fail=1
gen_exp_c > exp || framework_failure_
compare exp out || fail=1
rs=0 hd=33 ad=34 de=35 ln=36
returns_ 1 diff -u --color=always \
--palette="rs=0:hd=33:ad=34:de=35:ln=36" a b > out || fail=1
gen_exp_u > exp || framework_failure_
compare exp out || fail=1
# Before the fix in http://debbugs.gnu.org/22067,
# this test would trigger an infinite loop bug.
mkfifo fifo
printf '%*s-a' 1000000 > a
printf '%*s-b' 1000000 > b
head -c 10 < fifo > /dev/null &
diff --color=always ---presume-output-tty a b > fifo
test $? = 141 || fail=1
Exit $fail
@@ -0,0 +1,108 @@
#!/bin/sh
# This would malfunction in diff-3.4
. "${srcdir=.}/init.sh"; path_prepend_ ../src
# Some systems lack seq.
# A limited replacement for seq: handle 1 or 2 args; increment must be 1
seq()
{
case $# in
1) start=1 final=$1;;
2) start=$1 final=$2;;
*) echo you lose 1>&2; exit 1;;
esac
awk 'BEGIN{for(i='$start';i<='$final';i++) print i}' < /dev/null
}
echo a > a || framework_failure_
echo b > b || framework_failure_
echo c > c || framework_failure_
cat <<'EOF' > exp || framework_failure_
====
1:1c
a
2:1c
b
3:1c
c
EOF
fail=0
diff3 a b c > out 2> err || fail=1
compare exp out || fail=1
compare /dev/null err || fail=1
# Repeat, but with all three files the same:
diff3 a a a > out 2> err || fail=1
compare /dev/null out || fail=1
compare /dev/null err || fail=1
# This would have provoked a nontrivial leak prior to diffutils-3.5,
# due to the nontrivial list of diff_block structs.
seq 10 40|sed 's/1$/x/' > d || framework_failure_
seq 10 40|sed 's/5$/y/' > e || framework_failure_
seq 10 40|sed 's/8$/z/' > f || framework_failure_
cat <<'EOF' > exp40 || framework_failure_
====1
1:2c
1x
2:2c
3:2c
11
====2
1:6c
3:6c
15
2:6c
1y
====3
1:9c
2:9c
18
3:9c
1z
====1
1:12c
2x
2:12c
3:12c
21
====2
1:16c
3:16c
25
2:16c
2y
====3
1:19c
2:19c
28
3:19c
2z
====1
1:22c
3x
2:22c
3:22c
31
====2
1:26c
3:26c
35
2:26c
3y
====3
1:29c
2:29c
38
3:29c
3z
EOF
diff3 d e f > out 2> err
compare exp40 out || fail=1
compare /dev/null err || fail=1
Exit $fail
@@ -0,0 +1,65 @@
# -*- sh -*-
# Check environment variables for sane values while testing.
# Copyright (C) 2000-2017 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
as_unset=unset
else
as_unset=false
fi
envvar_check_fail=0
vars='
_POSIX2_VERSION
_STDBUF_E
_STDBUF_I
_STDBUF_O
BASH_ENV
BLOCKSIZE
BLOCK_SIZE
CDPATH
COLUMNS
DF_BLOCK_SIZE
DU_BLOCK_SIZE
EDITOR
ENV
GREP_OPTIONS
LANGUAGE
LS_BLOCK_SIZE
LS_COLORS
OMP_NUM_THREADS
POSIXLY_CORRECT
QUOTING_STYLE
SIMPLE_BACKUP_SUFFIX
TABSIZE
TERM
COLORTERM
TIME_STYLE
TMPDIR
VERSION_CONTROL
'
for var in $vars
do
$as_unset $var
if eval test \"\${$var+set}\" = set; then
echo "$0: the $var environment variable is set --" \
' unset it and rerun this test' >&2
envvar_check_fail=1
fi
done
test "$envvar_check_fail" = 1 && exit 1
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
# Ensure that no excess slash appears in diff -r output.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
mkdir -p a/f b/f/g || framework_failure_
echo Only in b/f: g > expected-out || framework_failure_
fail=0
diff -r a b/ > out 2> err && fail=1
# expect no stderr
compare /dev/null err || fail=1
compare expected-out out || fail=1
Exit $fail
@@ -0,0 +1,61 @@
#!/bin/sh
# filename quoting
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
cat <<EOF > exp- || fail=1
diff -N -r "a/ " "b/ "
0a1
> space
EOF
cat <<EOF > exp--u || fail=1
diff -N -r -u "a/ " "b/ "
--- "a/ "
+++ "b/ "
@@ -0,0 +1 @@
+space
EOF
cat <<EOF > exp--c || fail=1
diff -N -r -c "a/ " "b/ "
*** "a/ "
--- "b/ "
***************
*** 0 ****
--- 1 ----
+ space
EOF
mkdir a b
echo space > "b/ " || fail=1
for opt in '' -u -c; do
returns_ 1 diff -N -r $opt a b > out 2> err || fail=1
# Remove date and time.
sed -e 's/^\([-+*][-+*][-+*] [^ ]*\) .*/\1/' out > k; mv k out
compare exp-$(echo $opt|tr ' ' _) out || fail=1
done
rm -f "b/ "
cat <<EOF > exp || fail=1
--- "a/\t"
+++ "b/\001"
@@ -1 +1 @@
-tab
+one
EOF
tab=$(printf '\t')
x01=$(printf '\001')
echo tab > "a/$tab" || fail=1
echo one > "b/$x01" || fail=1
returns_ 1 diff -u "a/$tab" "b/$x01" > out 2> err || fail=1
# Remove date and time.
sed -e 's/^\([-+*][-+*][-+*] [^ ]*\) .*/\1/' out > k; mv k out
compare exp out || fail=1
Exit $fail
@@ -0,0 +1,65 @@
#!/bin/sh
# Demonstrate how -F RE behavior changed after diff-2.9.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
cat <<EOF > in || fail_ "failed to create temporary file"
procedure AdaCode is
procedure Local_Level_1 is
procedure Local_Level_2 is
procedure Local_Level_3 is
procedure Local_Level_4 is
procedure Local_Level_5 is
begin
null;
null;
null;
foo;
end;
begin
Local_Level_5;
end;
begin
Local_Level_4;
end;
begin
Local_Level_3;
end;
begin
Local_Level_2;
end;
begin
Local_Level_1;
end;
EOF
sed s/foo/null/ < in > in2 || fail_ "failed to create temporary file"
# Before diff-2.10, the function line would be truncated like this:
# @@ -8,7 +8,7 @@ procedure Local_Leve
cat <<EOF > exp || fail_ "failed to create temporary file"
@@ -8,7 +8,7 @@ procedure Local_Level_5 is
null;
null;
null;
- foo;
+ null;
end;
begin
Local_Level_5;
EOF
fail=0
returns_ 1 diff -u -F '^[[:space:]]*\(function\|procedure\)' in in2 \
> out 2> err || fail=1
sed -n '3,$p' out > k && mv k out || fail=1
compare exp out || fail=1
# expect empty stderr
compare /dev/null err || fail=1
Exit $fail
+269
View File
@@ -0,0 +1,269 @@
#! /bin/sh
# Make sure all these programs work properly
# when invoked with --help or --version.
# Copyright (C) 2000-2013, 2015-2017 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Ensure that $SHELL is set to *some* value and exported.
# This is required for dircolors, which would fail e.g., when
# invoked via debuild (which removes SHELL from the environment).
test "x$SHELL" = x && SHELL=/bin/sh
export SHELL
. "${srcdir=.}/init.sh"; path_prepend_ ../src
expected_failure_status_chroot=125
expected_failure_status_env=125
expected_failure_status_nice=125
expected_failure_status_nohup=125
expected_failure_status_stdbuf=125
expected_failure_status_su=125
expected_failure_status_timeout=125
expected_failure_status_printenv=2
expected_failure_status_tty=3
expected_failure_status_sort=2
expected_failure_status_expr=3
expected_failure_status_lbracket=2
expected_failure_status_dir=2
expected_failure_status_ls=2
expected_failure_status_vdir=2
expected_failure_status_cmp=2
expected_failure_status_zcmp=2
expected_failure_status_sdiff=2
expected_failure_status_diff3=2
expected_failure_status_diff=2
expected_failure_status_zdiff=2
expected_failure_status_zgrep=2
expected_failure_status_zegrep=2
expected_failure_status_zfgrep=2
expected_failure_status_grep=2
expected_failure_status_egrep=2
expected_failure_status_fgrep=2
test "$built_programs" \
|| fail_ "built_programs not specified!?!"
test "$VERSION" \
|| fail_ "set envvar VERSION; it is required for a PATH sanity-check"
# Extract version from --version output of the first program
for i in $built_programs; do
v=$(env $i --version | sed -n '1s/.* //p;q')
break
done
# Ensure that it matches $VERSION.
test "x$v" = "x$VERSION" \
|| fail_ "--version-\$VERSION mismatch"
for lang in C fr da; do
for i in $built_programs; do
# Skip 'test'; it doesn't accept --help or --version.
test $i = test && continue;
# false fails even when invoked with --help or --version.
if test $i = false; then
env LC_MESSAGES=$lang $i --help >/dev/null && fail=1
env LC_MESSAGES=$lang $i --version >/dev/null && fail=1
continue
fi
# The just-built install executable is always named 'ginstall'.
test $i = install && i=ginstall
# Make sure they exit successfully, under normal conditions.
env $i --help > h-$i || fail=1
env $i --version >/dev/null || fail=1
# Make sure they mention the bug-reporting address in --help output.
grep "$PACKAGE_BUGREPORT" h-$i > /dev/null || fail=1
rm -f h-$i
# Make sure they fail upon 'disk full' error.
if test -w /dev/full && test -c /dev/full; then
env $i --help >/dev/full 2>/dev/null && fail=1
env $i --version >/dev/full 2>/dev/null && fail=1
status=$?
test $i = [ && prog=lbracket || prog=$i
eval "expected=\$expected_failure_status_$prog"
test x$expected = x && expected=1
if test $status = $expected; then
: # ok
else
fail=1
echo "*** $i: bad exit status '$status' (expected $expected)," 1>&2
echo " with --help or --version output redirected to /dev/full" 1>&2
fi
fi
done
done
bigZ_in=bigZ-in.Z
zin=zin.gz
zin2=zin2.gz
tmp=tmp-$$
tmp_in=in-$$
tmp_in2=in2-$$
tmp_dir=dir-$$
tmp_out=out-$$
mkdir $tmp || fail=1
cd $tmp || fail=1
comm_setup () { args="$tmp_in $tmp_in"; }
csplit_setup () { args="$tmp_in //"; }
cut_setup () { args='-f 1'; }
join_setup () { args="$tmp_in $tmp_in"; }
tr_setup () { args='a a'; }
chmod_setup () { args="a+x $tmp_in"; }
# Punt on these.
chgrp_setup () { args=--version; }
chown_setup () { args=--version; }
mkfifo_setup () { args=--version; }
mknod_setup () { args=--version; }
# Punt on uptime, since it fails (e.g., failing to get boot time)
# on some systems, and we shouldn't let that stop 'make check'.
uptime_setup () { args=--version; }
# Create a file in the current directory, not in $TMPDIR.
mktemp_setup () { args=mktemp.XXXX; }
cmp_setup () { args="$tmp_in $tmp_in2"; }
# Tell dd not to print the line with transfer rate and total.
# The transfer rate would vary between runs.
dd_setup () { args=status=noxfer; }
zdiff_setup () { args="$zin $zin2"; }
zcmp_setup () { args="$zin $zin2"; }
zcat_setup () { args=$zin; }
gunzip_setup () { args=$zin; }
zmore_setup () { args=$zin; }
zless_setup () { args=$zin; }
znew_setup () { args=$bigZ_in; }
zforce_setup () { args=$zin; }
zgrep_setup () { args="z $zin"; }
zegrep_setup () { args="z $zin"; }
zfgrep_setup () { args="z $zin"; }
gzexe_setup () { args=$tmp_in; }
# We know that $tmp_in contains a "0"
grep_setup () { args="0 $tmp_in"; }
egrep_setup () { args="0 $tmp_in"; }
fgrep_setup () { args="0 $tmp_in"; }
diff_setup () { args="$tmp_in $tmp_in2"; }
sdiff_setup () { args="$tmp_in $tmp_in2"; }
diff3_setup () { args="$tmp_in $tmp_in2 $tmp_in2"; }
cp_setup () { args="$tmp_in $tmp_in2"; }
ln_setup () { args="$tmp_in ln-target"; }
ginstall_setup () { args="$tmp_in $tmp_in2"; }
mv_setup () { args="$tmp_in $tmp_in2"; }
mkdir_setup () { args=$tmp_dir/subdir; }
rmdir_setup () { args=$tmp_dir; }
rm_setup () { args=$tmp_in; }
shred_setup () { args=$tmp_in; }
touch_setup () { args=$tmp_in2; }
truncate_setup () { args="--reference=$tmp_in $tmp_in2"; }
basename_setup () { args=$tmp_in; }
dirname_setup () { args=$tmp_in; }
expr_setup () { args=foo; }
# Punt, in case GNU 'id' hasn't been installed yet.
groups_setup () { args=--version; }
pathchk_setup () { args=$tmp_in; }
yes_setup () { args=--version; }
logname_setup () { args=--version; }
nohup_setup () { args=--version; }
printf_setup () { args=foo; }
seq_setup () { args=10; }
sleep_setup () { args=0; }
su_setup () { args=--version; }
stdbuf_setup () { args="-oL true"; }
timeout_setup () { args=--version; }
# I'd rather not run sync, since it spins up disks that I've
# deliberately caused to spin down (but not unmounted).
sync_setup () { args=--version; }
test_setup () { args=foo; }
# This is necessary in the unusual event that there is
# no valid entry in /etc/mtab.
df_setup () { args=/; }
# This is necessary in the unusual event that getpwuid (getuid ()) fails.
id_setup () { args=-u; }
# Use env to avoid invoking built-in sleep of Solaris 11's /bin/sh.
kill_setup () {
env sleep 10m &
args=$!
}
link_setup () { args="$tmp_in link-target"; }
unlink_setup () { args=$tmp_in; }
readlink_setup () {
ln -s . slink
args=slink;
}
stat_setup () { args=$tmp_in; }
unlink_setup () { args=$tmp_in; }
lbracket_setup () { args=": ]"; }
# Ensure that each program "works" (exits successfully) when doing
# something more than --help or --version.
for i in $built_programs; do
# Skip these.
case $i in chroot|stty|tty|false|chcon|runcon) continue;; esac
rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out $bigZ_in $zin $zin2
echo z |gzip > $zin
cp $zin $zin2
cp $zin $bigZ_in
# This is sort of kludgey: use numbers so this is valid input for factor,
# and two tokens so it's valid input for tsort.
echo 2147483647 0 > $tmp_in
# Make $tmp_in2 identical. Then, using $tmp_in and $tmp_in2 as arguments
# to the likes of cmp and diff makes them exit successfully.
cp $tmp_in $tmp_in2
mkdir $tmp_dir
# echo ================== $i
test $i = [ && prog=lbracket || prog=$i
if type ${prog}_setup > /dev/null 2>&1; then
${prog}_setup
else
args=
fi
if env $i $args < $tmp_in > $tmp_out; then
: # ok
else
echo FAIL: $i
fail=1
fi
rm -rf $tmp_in $tmp_in2 $tmp_out $tmp_dir
done
Exit $fail
@@ -0,0 +1,46 @@
#!/bin/sh
# --ignore-matching-lines
# Bug reported by Vincent Lefevre in <http://bugs.gnu.org/16864>.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
cat <<'EOF' >a
1a
2
3a
4
5
6
EOF
cat <<'EOF' >b
1b
2
3b
4
5
6
7
EOF
cat <<'EOF' >exp
@@ -1,6 +1,7 @@
-1a
+1b
2
-3a
+3b
4
5
6
+7
EOF
returns_ 1 diff -u --ignore-matching-lines 3 a b >out 2>err || fail=1
sed 1,2d out >outtail || framework_failure+
compare exp outtail || fail=1
Exit $fail
@@ -0,0 +1,605 @@
# source this file; set up for tests
# Copyright (C) 2009-2017 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Using this file in a test
# =========================
#
# The typical skeleton of a test looks like this:
#
# #!/bin/sh
# . "${srcdir=.}/init.sh"; path_prepend_ .
# Execute some commands.
# Note that these commands are executed in a subdirectory, therefore you
# need to prepend "../" to relative filenames in the build directory.
# Note that the "path_prepend_ ." is useful only if the body of your
# test invokes programs residing in the initial directory.
# For example, if the programs you want to test are in src/, and this test
# script is named tests/test-1, then you would use "path_prepend_ ../src",
# or perhaps export PATH='$(abs_top_builddir)/src$(PATH_SEPARATOR)'"$$PATH"
# to all tests via automake's TESTS_ENVIRONMENT.
# Set the exit code 0 for success, 77 for skipped, or 1 or other for failure.
# Use the skip_ and fail_ functions to print a diagnostic and then exit
# with the corresponding exit code.
# Exit $?
# Executing a test that uses this file
# ====================================
#
# Running a single test:
# $ make check TESTS=test-foo.sh
#
# Running a single test, with verbose output:
# $ make check TESTS=test-foo.sh VERBOSE=yes
#
# Running a single test, keeping the temporary directory:
# $ make check TESTS=test-foo.sh KEEP=yes
#
# Running a single test, with single-stepping:
# 1. Go into a sub-shell:
# $ bash
# 2. Set relevant environment variables from TESTS_ENVIRONMENT in the
# Makefile:
# $ export srcdir=../../tests # this is an example
# 3. Execute the commands from the test, copy&pasting them one by one:
# $ . "$srcdir/init.sh"; path_prepend_ .
# ...
# 4. Finally
# $ exit
ME_=`expr "./$0" : '.*/\(.*\)$'`
# We use a trap below for cleanup. This requires us to go through
# hoops to get the right exit status transported through the handler.
# So use 'Exit STATUS' instead of 'exit STATUS' inside of the tests.
# Turn off errexit here so that we don't trip the bug with OSF1/Tru64
# sh inside this function.
Exit () { set +e; (exit $1); exit $1; }
# Print warnings (e.g., about skipped and failed tests) to this file number.
# Override by defining to say, 9, in init.cfg, and putting say,
# export ...ENVVAR_SETTINGS...; $(SHELL) 9>&2
# in the definition of TESTS_ENVIRONMENT in your tests/Makefile.am file.
# This is useful when using automake's parallel tests mode, to print
# the reason for skip/failure to console, rather than to the .log files.
: ${stderr_fileno_=2}
# Note that correct expansion of "$*" depends on IFS starting with ' '.
# Always write the full diagnostic to stderr.
# When stderr_fileno_ is not 2, also emit the first line of the
# diagnostic to that file descriptor.
warn_ ()
{
# If IFS does not start with ' ', set it and emit the warning in a subshell.
case $IFS in
' '*) printf '%s\n' "$*" >&2
test $stderr_fileno_ = 2 \
|| { printf '%s\n' "$*" | sed 1q >&$stderr_fileno_ ; } ;;
*) (IFS=' '; warn_ "$@");;
esac
}
fail_ () { warn_ "$ME_: failed test: $@"; Exit 1; }
skip_ () { warn_ "$ME_: skipped test: $@"; Exit 77; }
fatal_ () { warn_ "$ME_: hard error: $@"; Exit 99; }
framework_failure_ () { warn_ "$ME_: set-up failure: $@"; Exit 99; }
# This is used to simplify checking of the return value
# which is useful when ensuring a command fails as desired.
# I.e., just doing `command ... &&fail=1` will not catch
# a segfault in command for example. With this helper you
# instead check an explicit exit code like
# returns_ 1 command ... || fail
returns_ () {
# Disable tracing so it doesn't interfere with stderr of the wrapped command
{ set +x; } 2>/dev/null
local exp_exit="$1"
shift
"$@"
test $? -eq $exp_exit && ret_=0 || ret_=1
if test "$VERBOSE" = yes && test "$gl_set_x_corrupts_stderr_" = false; then
set -x
fi
{ return $ret_; } 2>/dev/null
}
# Sanitize this shell to POSIX mode, if possible.
DUALCASE=1; export DUALCASE
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
else
case `(set -o) 2>/dev/null` in
*posix*) set -o posix ;;
esac
fi
# We require $(...) support unconditionally.
# We require non-surprising "local" semantics (this eliminates dash).
# This takes the admittedly draconian step of eliminating dash, because the
# assignment tab=$(printf '\t') works fine, yet preceding it with "local "
# transforms it into an assignment that sets the variable to the empty string.
# That is too counter-intuitive, and can lead to subtle run-time malfunction.
# The example below is less subtle in that with dash, it evokes the run-time
# exception "dash: 1: local: 1: bad variable name".
# We require a few additional shell features only when $EXEEXT is nonempty,
# in order to support automatic $EXEEXT emulation:
# - hyphen-containing alias names
# - we prefer to use ${var#...} substitution, rather than having
# to work around lack of support for that feature.
# The following code attempts to find a shell with support for these features.
# If the current shell passes the test, we're done. Otherwise, test other
# shells until we find one that passes. If one is found, re-exec it.
# If no acceptable shell is found, skip the current test.
#
# The "...set -x; P=1 true 2>err..." test is to disqualify any shell that
# emits "P=1" into err, as /bin/sh from SunOS 5.11 and OpenBSD 4.7 do.
#
# Use "9" to indicate success (rather than 0), in case some shell acts
# like Solaris 10's /bin/sh but exits successfully instead of with status 2.
# Eval this code in a subshell to determine a shell's suitability.
# 10 - passes all tests; ok to use
# 9 - ok, but enabling "set -x" corrupts app stderr; prefer higher score
# ? - not ok
gl_shell_test_script_='
test $(echo y) = y || exit 1
f_local_() { local v=1; }; f_local_ || exit 1
f_dash_local_fail_() { local t=$(printf " 1"); }; f_dash_local_fail_
score_=10
if test "$VERBOSE" = yes; then
test -n "$( (exec 3>&1; set -x; P=1 true 2>&3) 2> /dev/null)" && score_=9
fi
test -z "$EXEEXT" && exit $score_
shopt -s expand_aliases
alias a-b="echo zoo"
v=abx
test ${v%x} = ab \
&& test ${v#a} = bx \
&& test $(a-b) = zoo \
&& exit $score_
'
if test "x$1" = "x--no-reexec"; then
shift
else
# Assume a working shell. Export to subshells (setup_ needs this).
gl_set_x_corrupts_stderr_=false
export gl_set_x_corrupts_stderr_
# Record the first marginally acceptable shell.
marginal_=
# Search for a shell that meets our requirements.
for re_shell_ in __current__ "${CONFIG_SHELL:-no_shell}" \
/bin/sh bash dash zsh pdksh fail
do
test "$re_shell_" = no_shell && continue
# If we've made it all the way to the sentinel, "fail" without
# finding even a marginal shell, skip this test.
if test "$re_shell_" = fail; then
test -z "$marginal_" && skip_ failed to find an adequate shell
re_shell_=$marginal_
break
fi
# When testing the current shell, simply "eval" the test code.
# Otherwise, run it via $re_shell_ -c ...
if test "$re_shell_" = __current__; then
# 'eval'ing this code makes Solaris 10's /bin/sh exit with
# $? set to 2. It does not evaluate any of the code after the
# "unexpected" first '('. Thus, we must run it in a subshell.
( eval "$gl_shell_test_script_" ) > /dev/null 2>&1
else
"$re_shell_" -c "$gl_shell_test_script_" 2>/dev/null
fi
st_=$?
# $re_shell_ works just fine. Use it.
if test $st_ = 10; then
gl_set_x_corrupts_stderr_=false
break
fi
# If this is our first marginally acceptable shell, remember it.
if test "$st_:$marginal_" = 9: ; then
marginal_="$re_shell_"
gl_set_x_corrupts_stderr_=true
fi
done
if test "$re_shell_" != __current__; then
# Found a usable shell. Preserve -v and -x.
case $- in
*v*x* | *x*v*) opts_=-vx ;;
*v*) opts_=-v ;;
*x*) opts_=-x ;;
*) opts_= ;;
esac
re_shell=$re_shell_
export re_shell
exec "$re_shell_" $opts_ "$0" --no-reexec "$@"
echo "$ME_: exec failed" 1>&2
exit 127
fi
fi
# If this is bash, turn off all aliases.
test -n "$BASH_VERSION" && unalias -a
# Note that when supporting $EXEEXT (transparently mapping from PROG_NAME to
# PROG_NAME.exe), we want to support hyphen-containing names like test-acos.
# That is part of the shell-selection test above. Why use aliases rather
# than functions? Because support for hyphen-containing aliases is more
# widespread than that for hyphen-containing function names.
test -n "$EXEEXT" && shopt -s expand_aliases
# Enable glibc's malloc-perturbing option.
# This is useful for exposing code that depends on the fact that
# malloc-related functions often return memory that is mostly zeroed.
# If you have the time and cycles, use valgrind to do an even better job.
: ${MALLOC_PERTURB_=87}
export MALLOC_PERTURB_
# This is a stub function that is run upon trap (upon regular exit and
# interrupt). Override it with a per-test function, e.g., to unmount
# a partition, or to undo any other global state changes.
cleanup_ () { :; }
# Emit a header similar to that from diff -u; Print the simulated "diff"
# command so that the order of arguments is clear. Don't bother with @@ lines.
emit_diff_u_header_ ()
{
printf '%s\n' "diff -u $*" \
"--- $1 1970-01-01" \
"+++ $2 1970-01-01"
}
# Arrange not to let diff or cmp operate on /dev/null,
# since on some systems (at least OSF/1 5.1), that doesn't work.
# When there are not two arguments, or no argument is /dev/null, return 2.
# When one argument is /dev/null and the other is not empty,
# cat the nonempty file to stderr and return 1.
# Otherwise, return 0.
compare_dev_null_ ()
{
test $# = 2 || return 2
if test "x$1" = x/dev/null; then
test -s "$2" || return 0
emit_diff_u_header_ "$@"; sed 's/^/+/' "$2"
return 1
fi
if test "x$2" = x/dev/null; then
test -s "$1" || return 0
emit_diff_u_header_ "$@"; sed 's/^/-/' "$1"
return 1
fi
return 2
}
for diff_opt_ in -u -U3 -c '' no; do
test "$diff_opt_" != no &&
diff_out_=`exec 2>/dev/null; diff $diff_opt_ "$0" "$0" < /dev/null` &&
break
done
if test "$diff_opt_" != no; then
if test -z "$diff_out_"; then
compare_ () { diff $diff_opt_ "$@"; }
else
compare_ ()
{
# If no differences were found, AIX and HP-UX 'diff' produce output
# like "No differences encountered". Hide this output.
diff $diff_opt_ "$@" > diff.out
diff_status_=$?
test $diff_status_ -eq 0 || cat diff.out || diff_status_=2
rm -f diff.out || diff_status_=2
return $diff_status_
}
fi
elif cmp -s /dev/null /dev/null 2>/dev/null; then
compare_ () { cmp -s "$@"; }
else
compare_ () { cmp "$@"; }
fi
# Usage: compare EXPECTED ACTUAL
#
# Given compare_dev_null_'s preprocessing, defer to compare_ if 2 or more.
# Otherwise, propagate $? to caller: any diffs have already been printed.
compare ()
{
# This looks like it can be factored to use a simple "case $?"
# after unchecked compare_dev_null_ invocation, but that would
# fail in a "set -e" environment.
if compare_dev_null_ "$@"; then
return 0
else
case $? in
1) return 1;;
*) compare_ "$@";;
esac
fi
}
# An arbitrary prefix to help distinguish test directories.
testdir_prefix_ () { printf gt; }
# Run the user-overridable cleanup_ function, remove the temporary
# directory and exit with the incoming value of $?.
remove_tmp_ ()
{
__st=$?
cleanup_
if test "$KEEP" = yes; then
echo "Not removing temporary directory $test_dir_"
else
# cd out of the directory we're about to remove
cd "$initial_cwd_" || cd / || cd /tmp
chmod -R u+rwx "$test_dir_"
# If removal fails and exit status was to be 0, then change it to 1.
rm -rf "$test_dir_" || { test $__st = 0 && __st=1; }
fi
exit $__st
}
# Given a directory name, DIR, if every entry in it that matches *.exe
# contains only the specified bytes (see the case stmt below), then print
# a space-separated list of those names and return 0. Otherwise, don't
# print anything and return 1. Naming constraints apply also to DIR.
find_exe_basenames_ ()
{
feb_dir_=$1
feb_fail_=0
feb_result_=
feb_sp_=
for feb_file_ in $feb_dir_/*.exe; do
# If there was no *.exe file, or there existed a file named "*.exe" that
# was deleted between the above glob expansion and the existence test
# below, just skip it.
test "x$feb_file_" = "x$feb_dir_/*.exe" && test ! -f "$feb_file_" \
&& continue
# Exempt [.exe, since we can't create a function by that name, yet
# we can't invoke [ by PATH search anyways due to shell builtins.
test "x$feb_file_" = "x$feb_dir_/[.exe" && continue
case $feb_file_ in
*[!-a-zA-Z/0-9_.+]*) feb_fail_=1; break;;
*) # Remove leading file name components as well as the .exe suffix.
feb_file_=${feb_file_##*/}
feb_file_=${feb_file_%.exe}
feb_result_="$feb_result_$feb_sp_$feb_file_";;
esac
feb_sp_=' '
done
test $feb_fail_ = 0 && printf %s "$feb_result_"
return $feb_fail_
}
# Consider the files in directory, $1.
# For each file name of the form PROG.exe, create an alias named
# PROG that simply invokes PROG.exe, then return 0. If any selected
# file name or the directory name, $1, contains an unexpected character,
# define no alias and return 1.
create_exe_shims_ ()
{
case $EXEEXT in
'') return 0 ;;
.exe) ;;
*) echo "$0: unexpected \$EXEEXT value: $EXEEXT" 1>&2; return 1 ;;
esac
base_names_=`find_exe_basenames_ $1` \
|| { echo "$0 (exe_shim): skipping directory: $1" 1>&2; return 0; }
if test -n "$base_names_"; then
for base_ in $base_names_; do
alias "$base_"="$base_$EXEEXT"
done
fi
return 0
}
# Use this function to prepend to PATH an absolute name for each
# specified, possibly-$initial_cwd_-relative, directory.
path_prepend_ ()
{
while test $# != 0; do
path_dir_=$1
case $path_dir_ in
'') fail_ "invalid path dir: '$1'";;
/*) abs_path_dir_=$path_dir_;;
*) abs_path_dir_=$initial_cwd_/$path_dir_;;
esac
case $abs_path_dir_ in
*:*) fail_ "invalid path dir: '$abs_path_dir_'";;
esac
PATH="$abs_path_dir_:$PATH"
# Create an alias, FOO, for each FOO.exe in this directory.
create_exe_shims_ "$abs_path_dir_" \
|| fail_ "something failed (above): $abs_path_dir_"
shift
done
export PATH
}
setup_ ()
{
if test "$VERBOSE" = yes; then
# Test whether set -x may cause the selected shell to corrupt an
# application's stderr. Many do, including zsh-4.3.10 and the /bin/sh
# from SunOS 5.11, OpenBSD 4.7 and Irix 5.x and 6.5.
# If enabling verbose output this way would cause trouble, simply
# issue a warning and refrain.
if $gl_set_x_corrupts_stderr_; then
warn_ "using SHELL=$SHELL with 'set -x' corrupts stderr"
else
set -x
fi
fi
initial_cwd_=$PWD
pfx_=`testdir_prefix_`
test_dir_=`mktempd_ "$initial_cwd_" "$pfx_-$ME_.XXXX"` \
|| fail_ "failed to create temporary directory in $initial_cwd_"
cd "$test_dir_" || fail_ "failed to cd to temporary directory"
# As autoconf-generated configure scripts do, ensure that IFS
# is defined initially, so that saving and restoring $IFS works.
gl_init_sh_nl_='
'
IFS=" "" $gl_init_sh_nl_"
# This trap statement, along with a trap on 0 below, ensure that the
# temporary directory, $test_dir_, is removed upon exit as well as
# upon receipt of any of the listed signals.
for sig_ in 1 2 3 13 15; do
eval "trap 'Exit $(expr $sig_ + 128)' $sig_"
done
}
# Create a temporary directory, much like mktemp -d does.
# Written by Jim Meyering.
#
# Usage: mktempd_ /tmp phoey.XXXXXXXXXX
#
# First, try to use the mktemp program.
# Failing that, we'll roll our own mktemp-like function:
# - try to get random bytes from /dev/urandom
# - failing that, generate output from a combination of quickly-varying
# sources and gzip. Ignore non-varying gzip header, and extract
# "random" bits from there.
# - given those bits, map to file-name bytes using tr, and try to create
# the desired directory.
# - make only $MAX_TRIES_ attempts
# Helper function. Print $N pseudo-random bytes from a-zA-Z0-9.
rand_bytes_ ()
{
n_=$1
# Maybe try openssl rand -base64 $n_prime_|tr '+/=\012' abcd first?
# But if they have openssl, they probably have mktemp, too.
chars_=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
dev_rand_=/dev/urandom
if test -r "$dev_rand_"; then
# Note: 256-length($chars_) == 194; 3 copies of $chars_ is 186 + 8 = 194.
dd ibs=$n_ count=1 if=$dev_rand_ 2>/dev/null \
| LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_
return
fi
n_plus_50_=`expr $n_ + 50`
cmds_='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n'
data_=` (eval "$cmds_") 2>&1 | gzip `
# Ensure that $data_ has length at least 50+$n_
while :; do
len_=`echo "$data_"|wc -c`
test $n_plus_50_ -le $len_ && break;
data_=` (echo "$data_"; eval "$cmds_") 2>&1 | gzip `
done
echo "$data_" \
| dd bs=1 skip=50 count=$n_ 2>/dev/null \
| LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_
}
mktempd_ ()
{
case $# in
2);;
*) fail_ "Usage: mktempd_ DIR TEMPLATE";;
esac
destdir_=$1
template_=$2
MAX_TRIES_=4
# Disallow any trailing slash on specified destdir:
# it would subvert the post-mktemp "case"-based destdir test.
case $destdir_ in
/ | //) destdir_slash_=$destdir;;
*/) fail_ "invalid destination dir: remove trailing slash(es)";;
*) destdir_slash_=$destdir_/;;
esac
case $template_ in
*XXXX) ;;
*) fail_ \
"invalid template: $template_ (must have a suffix of at least 4 X's)";;
esac
# First, try to use mktemp.
d=`unset TMPDIR; { mktemp -d -t -p "$destdir_" "$template_"; } 2>/dev/null` &&
# The resulting name must be in the specified directory.
case $d in "$destdir_slash_"*) :;; *) false;; esac &&
# It must have created the directory.
test -d "$d" &&
# It must have 0700 permissions. Handle sticky "S" bits.
perms=`ls -dgo "$d" 2>/dev/null` &&
case $perms in drwx--[-S]---*) :;; *) false;; esac && {
echo "$d"
return
}
# If we reach this point, we'll have to create a directory manually.
# Get a copy of the template without its suffix of X's.
base_template_=`echo "$template_"|sed 's/XX*$//'`
# Calculate how many X's we've just removed.
template_length_=`echo "$template_" | wc -c`
nx_=`echo "$base_template_" | wc -c`
nx_=`expr $template_length_ - $nx_`
err_=
i_=1
while :; do
X_=`rand_bytes_ $nx_`
candidate_dir_="$destdir_slash_$base_template_$X_"
err_=`mkdir -m 0700 "$candidate_dir_" 2>&1` \
&& { echo "$candidate_dir_"; return; }
test $MAX_TRIES_ -le $i_ && break;
i_=`expr $i_ + 1`
done
fail_ "$err_"
}
# If you want to override the testdir_prefix_ function,
# or to add more utility functions, use this file.
test -f "$srcdir/init.cfg" \
&& . "$srcdir/init.cfg"
setup_ "$@"
# This trap is here, rather than in the setup_ function, because some
# shells run the exit trap at shell function exit, rather than script exit.
trap remove_tmp_ 0
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
# Ensure we diagnose and fail upon first invalid -I regex.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
echo > a || framework_failure_
echo b > b || framework_failure_
echo 'diff: \: Trailing backslash' > exp-err || framework_failure_
# This must fail with an exit status of 2:
returns_ 2 diff -Ix -I\\ a b > out 2> err || fail=1
compare /dev/null out || fail=1
compare exp-err err || fail=1
Exit $fail
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh
# Show how diff's -p option can mistakenly match a label: in column 1.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
cat <<EOF > exp || fail=1
@@ -4 +4 @@ label:
-1;
+2;
EOF
cat <<EOF > a || fail=1
func ()
{
label:
1;
}
EOF
sed s/1/2/ a > b || fail=1
returns_ 1 diff -p -u0 a b > out 2> err || fail=1
tail -3 out > k && mv k out || fail=1
compare exp out || fail=1
# expect empty stderr
compare /dev/null err || fail=1
Exit $fail
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
# Test --new-file (-N) and --unidirectional-new-file.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
echo a > a || fail=1
echo '0a1
> a' > exp || fail=1
returns_ 1 diff -N - a <&- > out || fail=1
compare exp out || fail=1
returns_ 1 diff --unidirectional-new-file - a <&- > out || fail=1
compare exp out || fail=1
returns_ 1 diff -N b - < a > out || fail=1
compare exp out || fail=1
returns_ 1 diff --unidirectional-new-file b - < a > out || fail=1
compare exp out || fail=1
echo '1d0
< a' > exp || fail=1
returns_ 1 diff -N a - <&- > out || fail=1
compare exp out || fail=1
# With closed standard input, require an exit status of 2
# and empty stdout.
returns_ 2 diff --unidirectional-new-file a - <&- > out || fail=1
compare /dev/null out || fail=1
returns_ 1 diff -N - b < a > out || fail=1
compare exp out || fail=1
returns_ 2 diff --unidirectional-new-file - b < a > out || fail=1
Exit $fail
@@ -0,0 +1,155 @@
#!/bin/sh
# Test the --no-dereference option.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
echo 'Simple contents' > regular1
echo 'Sample contents' > regular2
echo 'Sample contents' > regular3
ln -s regular1 symlink1
ln -s regular1 symlink1bis
ln -s regular2 symlink2
ln -s regular3 symlink3
# Non-recursive comparisons.
# Test case 3: Compare regular file with regular file.
returns_ 1 diff --no-dereference regular1 regular2 > out || fail=1
cat <<EOF > expected || framework_failure_
1c1
< Simple contents
---
> Sample contents
EOF
compare expected out || fail=1
# Test case 4: Compare regular file with symbolic link.
returns_ 1 diff --no-dereference regular1 symlink1 > out || fail=1
cat <<EOF > expected || framework_failure_
File regular1 is a regular file while file symlink1 is a symbolic link
EOF
compare expected out || fail=1
# Test case 5: Compare symbolic link with regular file.
returns_ 1 diff --no-dereference symlink1 regular1 > out || fail=1
cat <<EOF > expected || framework_failure_
File symlink1 is a symbolic link while file regular1 is a regular file
EOF
compare expected out || fail=1
# Test case 6: Compare symbolic links with same value.
diff --no-dereference symlink1 symlink1bis > out || fail=1
compare /dev/null out || fail=1
# Test case 7: Compare symbolic links with different value and different target
# contents.
returns_ 1 diff --no-dereference symlink1 symlink2 > out || fail=1
cat <<EOF > expected || framework_failure_
Symbolic links symlink1 and symlink2 differ
EOF
compare expected out || fail=1
# Test case 8: Compare symbolic links with different value and same target
# contents.
returns_ 1 diff --no-dereference symlink2 symlink3 > out || fail=1
cat <<EOF > expected || framework_failure_
Symbolic links symlink2 and symlink3 differ
EOF
compare expected out || fail=1
# Recursive comparisons.
# Test case 1: Compare symbolic link with nonexistent file.
mkdir subdir1a
mkdir subdir1b
ln -s nonexistent subdir1a/foo
ln -s ../regular1 subdir1a/bar
returns_ 1 diff -r --no-dereference subdir1a subdir1b > out || fail=1
cat <<EOF > expected || framework_failure_
Only in subdir1a: bar
Only in subdir1a: foo
EOF
compare expected out || fail=1
# Test case 1: Compare nonexistent file with symbolic link.
mkdir subdir2a
mkdir subdir2b
ln -s nonexistent subdir2b/foo
ln -s ../regular1 subdir2b/bar
returns_ 1 diff -r --no-dereference subdir2a subdir2b > out || fail=1
cat <<EOF > expected || framework_failure_
Only in subdir2b: bar
Only in subdir2b: foo
EOF
compare expected out || fail=1
# Test case 3: Compare regular file with regular file.
mkdir subdir3a
mkdir subdir3b
cp regular1 subdir3a/foo
cp regular2 subdir3b/foo
returns_ 1 diff -r --no-dereference subdir3a subdir3b > out || fail=1
cat <<EOF > expected || framework_failure_
diff -r --no-dereference subdir3a/foo subdir3b/foo
1c1
< Simple contents
---
> Sample contents
EOF
compare expected out || fail=1
# Test case 4: Compare regular file with symbolic link.
mkdir subdir4a
mkdir subdir4b
cp regular1 subdir4a/foo
ln -s ../regular1 subdir4b/foo
returns_ 1 diff -r --no-dereference subdir4a subdir4b > out || fail=1
cat <<EOF > expected || framework_failure_
File subdir4a/foo is a regular file while file subdir4b/foo is a symbolic link
EOF
compare expected out || fail=1
# Test case 5: Compare symbolic link with regular file.
mkdir subdir5a
mkdir subdir5b
ln -s ../regular1 subdir5a/foo
cp regular1 subdir5b/foo
returns_ 1 diff -r --no-dereference subdir5a subdir5b > out || fail=1
cat <<EOF > expected || framework_failure_
File subdir5a/foo is a symbolic link while file subdir5b/foo is a regular file
EOF
compare expected out || fail=1
# Test case 6: Compare symbolic links with same value.
mkdir subdir6a
mkdir subdir6b
ln -s ../regular1 subdir6a/foo
ln -s ../regular1 subdir6b/foo
diff -r --no-dereference subdir6a subdir6b > out || fail=1
compare /dev/null out || fail=1
# Test case 7: Compare symbolic links with different value and different target
# contents.
mkdir subdir7a
mkdir subdir7b
ln -s ../regular1 subdir7a/foo
ln -s ../regular2 subdir7b/foo
returns_ 1 diff -r --no-dereference subdir7a subdir7b > out || fail=1
cat <<EOF > expected || framework_failure_
Symbolic links subdir7a/foo and subdir7b/foo differ
EOF
compare expected out || fail=1
# Test case 8: Compare symbolic links with different value and same target
# contents.
mkdir subdir8a
mkdir subdir8b
ln -s ../regular2 subdir8a/foo
ln -s ../regular3 subdir8b/foo
returns_ 1 diff -r --no-dereference subdir8a subdir8b > out || fail=1
cat <<EOF > expected || framework_failure_
Symbolic links subdir8a/foo and subdir8b/foo differ
EOF
compare expected out || fail=1
Exit $fail
@@ -0,0 +1,56 @@
#!/bin/sh
# exercise the no-newline-at-EOF bug
# Before the April 2010 fix, the "\ No newline at end of file"
# line would not be printed.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
printf '\n1' > a || framework_failure_
printf '\n0\n\n1' > b || framework_failure_
cat <<EOF > exp || framework_failure_
@@ -1,2 +1,4 @@
+0
+
1
\ No newline at end of file
EOF
cat <<EOF > exp2 || framework_failure_
@@ -1,2 +1,4 @@
-1
+0
+
+1
\ No newline at end of file
EOF
fail=0
# So we don't have to record trailing blanks in expected output above.
opt=--suppress-blank-empty
returns_ 1 diff $opt -U1 a b > out 2> err || fail=1
sed -n '/^@@/,$p' out > k && mv k out || fail=1
compare exp out || fail=1
# expect empty stderr
compare /dev/null err || fail=1
# Repeat, but with a newline at the end of "a".
echo >> a
returns_ 1 diff $opt -U1 a b > out 2> err || fail=1
sed -n '/^@@/,$p' out > k && mv k out || fail=1
compare exp2 out || fail=1
# expect empty stderr
compare /dev/null err || fail=1
# Test for Bug#18402.
printf a > a
printf b > b
returns_ 1 diff -B a b > out 2>err || fail=1
Exit $fail
+24
View File
@@ -0,0 +1,24 @@
#!/bin/sh
# Ensure that "-" means "standard input".
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
cat <<EOF > exp || fail=1
--- -
+++ b
@@ -1 +1 @@
-a
+b
EOF
echo a > a
echo b > b
returns_ 1 diff -u - b < a > out 2> err || fail=1
# Remove date and time.
sed -e 's/^\([-+*][-+*][-+*] [^ ]*\) .*/\1/' out > k; mv k out
compare exp out || fail=1
Exit $fail
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
# Check that diff responds well with two different file names
# that compare equal with strcoll. See:
# http://lists.gnu.org/archive/html/bug-diffutils/2013-03/msg00012.html
. "${srcdir=.}/init.sh"; path_prepend_ ../src
# These two names compare equal in the en_US.UTF-8 locale
# in current (2013) versions of glibc.
# On systems where the names do not compare equal,
# this diff test should still do the right thing.
LC_ALL=en_US.UTF-8
export LC_ALL
name1='エンドカード1'
name2='ブックレット1'
mkdir d1 d2 || fail=1
echo x >d1/"$name1" || fail=1
echo x >d2/"$name2" || fail=1
# This should report a difference, but on the affected systems
# diffutils 3.3 does not.
diff d1 d2 && fail=1
Exit $fail