2 # Ensure that shuf randomizes its input.
4 # Copyright (C) 2006-2023 Free Software Foundation, Inc.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <https://www.gnu.org/licenses/>.
19 .
"${srcdir=.}/tests/init.sh"; path_prepend_ .
/src
23 seq 100 > in || framework_failure_
25 shuf
in >out || fail
=1
27 # Fail if the input is the same as the output.
28 # This is a probabilistic test :-)
29 # However, the odds of failure are very low: 1 in 100! (~ 1 in 10^158)
30 compare
in out
> /dev
/null
&& { fail
=1; echo "not random?" 1>&2; }
32 # Fail if the sorted output is not the same as the input.
34 compare
in out1 ||
{ fail
=1; echo "not a permutation" 1>&2; }
36 # Exercise shuf's -i option.
37 shuf
-i 1-100 > out || fail
=1
38 compare
in out
> /dev
/null
&& { fail
=1; echo "not random?" 1>&2; }
40 compare
in out1 ||
{ fail
=1; echo "not a permutation" 1>&2; }
42 # Exercise shuf's -r -n 0 options, with no standard input.
43 shuf
-r -n 0 in <&- >out || fail
=1
44 compare
/dev
/null out || fail
=1
46 # Exercise shuf's -e option.
47 t
=$
(shuf
-e a b c d e |
sort |
fmt)
48 test "$t" = 'a b c d e' ||
{ fail
=1; echo "not a permutation" 1>&2; }
50 # coreutils-8.22 dumps core.
52 test $?
-eq 1 || fail
=1
54 # coreutils-8.22 and 8.23 dump core
55 # with a single redundant operand with --input-range
57 test $?
-eq 1 || fail
=1
59 # Before coreutils-6.3, this would infloop.
60 # "seq 1860" produces 8193 (8K + 1) bytes of output.
61 seq 1860 | shuf
> /dev
/null || fail
=1
63 # coreutils-6.12 and earlier would output a newline terminator, not \0.
64 shuf
--zero-terminated -i 1-1 > out || fail
=1
65 printf '1\0' > exp || framework_failure_
66 cmp out exp ||
{ fail
=1; echo "missing NUL terminator?" 1>&2; }
68 # Ensure shuf -n operates efficiently for small n. Before coreutils-8.13
69 # this would try to allocate $SIZE_MAX * sizeof(size_t)
70 timeout
10 shuf
-i1-$SIZE_MAX -n2 >/dev
/null ||
71 { fail
=1; echo "couldn't get a small subset" >&2; }
73 # Ensure shuf -n0 doesn't read any input or open specified files
74 touch unreadable || framework_failure_
75 chmod 0 unreadable || framework_failure_
76 if ! test -r unreadable
; then
77 shuf
-n0 unreadable || fail
=1
78 { shuf
-n1 unreadable ||
test $?
-ne 1; } && fail
=1
81 # Multiple -n is accepted, should use the smallest value
82 shuf
-n10 -i0-9 -n3 -n20 > exp || framework_failure_
83 c
=$
(wc -l < exp
) || framework_failure_
84 test "$c" -eq 3 ||
{ fail
=1; echo "Multiple -n failed">&2 ; }
86 # Test error conditions
88 # -i and -e must not be used together
89 : |
{ shuf
-i0-9 -e A B ||
test $?
-ne 1; } &&
90 { fail
=1; echo "shuf did not detect erroneous -e and -i usage.">&2 ; }
91 # Test invalid value for -n
92 : |
{ shuf
-nA ||
test $?
-ne 1; } &&
93 { fail
=1; echo "shuf did not detect erroneous -n usage.">&2 ; }
95 { shuf
-i0-9 -n10 -i8-90 ||
test $?
-ne 1; } &&
96 { fail
=1; echo "shuf did not detect multiple -i usage.">&2 ; }
98 for ARG
in '1' 'A' '1-' '1-A'; do
99 { shuf
-i$ARG ||
test $?
-ne 1; } &&
100 { fail
=1; echo "shuf did not detect erroneous -i$ARG usage.">&2 ; }
103 # multiple -o are forbidden
104 { shuf
-i0-9 -o A
-o B ||
test $?
-ne 1; } &&
105 { fail
=1; echo "shuf did not detect erroneous multiple -o usage.">&2 ; }
106 # multiple random-sources are forbidden
107 { shuf
-i0-9 --random-source A
--random-source B ||
test $?
-ne 1; } &&
108 { fail
=1; echo "shuf did not detect multiple --random-source usage.">&2 ; }
110 # Test --repeat option
112 # --repeat without count should return an indefinite number of lines
113 shuf
--rep -i 0-10 |
head -n 1000 > exp || framework_failure_
114 c
=$
(wc -l < exp
) || framework_failure_
116 ||
{ fail
=1; echo "--repeat does not repeat indefinitely">&2 ; }
118 # --repeat can output more values than the input range
119 shuf
--rep -i0-9 -n1000 > exp || framework_failure_
120 c
=$
(wc -l < exp
) || framework_failure_
121 test "$c" -eq 1000 ||
{ fail
=1; echo "--repeat with --count failed">&2 ; }
123 # Check output values (this is not bullet-proof, but drawing 1000 values
124 # between 0 and 9 should produce all values, unless there's a bug in shuf
125 # or a very poor random source, or extremely bad luck)
126 c
=$
(sort -nu exp |
paste -s -d ' ') || framework_failure_
127 test "$c" = "0 1 2 3 4 5 6 7 8 9" ||
128 { fail
=1; echo "--repeat produced bad output">&2 ; }
130 # check --repeat with non-zero low value
131 shuf
--rep -i222-233 -n2000 > exp || framework_failure_
132 c
=$
(sort -nu exp |
paste -s -d ' ') || framework_failure_
133 test "$c" = "222 223 224 225 226 227 228 229 230 231 232 233" ||
134 { fail
=1; echo "--repeat produced bad output with non-zero low">&2 ; }
136 # --repeat,-i,count=0 should not fail and produce no output
137 shuf
--rep -i0-9 -n0 > exp || framework_failure_
138 # file size should be zero (no output from shuf)
140 { fail
=1; echo "--repeat,-i0-9,-n0 produced bad output">&2 ; }
142 # --repeat with -e, without count, should repeat indefinitely
143 shuf
--rep -e A B C D |
head -n 1000 > exp || framework_failure_
144 c
=$
(wc -l < exp
) || framework_failure_
145 test "$c" -eq 1000 ||
146 { fail
=1; echo "--repeat,-e does not repeat indefinitely">&2 ; }
148 # --repeat with STDIN, without count, should repeat indefinitely
149 printf "A\nB\nC\nD\nE\n" | shuf
--rep |
head -n 1000 > exp || framework_failure_
150 c
=$
(wc -l < exp
) || framework_failure_
151 test "$c" -eq 1000 ||
152 { fail
=1; echo "--repeat,STDIN does not repeat indefinitely">&2 ; }
154 # --repeat with STDIN,count - can return move values than input lines
155 printf "A\nB\nC\nD\nE\n" | shuf
--rep -n2000 > exp || framework_failure_
156 c
=$
(wc -l < exp
) || framework_failure_
157 test "$c" -eq 2000 ||
158 { fail
=1; echo "--repeat,STDIN,count failed">&2 ; }
160 # Check output values (this is not bullet-proof, but drawing 2000 values
161 # between A and E should produce all values, unless there's a bug in shuf
162 # or a very poor random source, or extremely bad luck)
163 c
=$
(sort -u exp |
paste -s -d ' ') || framework_failure_
164 test "$c" = "A B C D E" ||
165 { fail
=1; echo "--repeat,STDIN,count produced bad output">&2 ; }
167 # --repeat,stdin,count=0 should not fail and produce no output
168 printf "A\nB\nC\nD\nE\n" | shuf
--rep -n0 > exp || framework_failure_
169 # file size should be zero (no output from shuf)
171 { fail
=1; echo "--repeat,STDIN,-n0 produced bad output">&2 ; }
173 # shuf 8.25 mishandles input if stdin is closed, due to glibc bug#15589.
174 # See coreutils bug#25029.
175 shuf
/dev
/null
<&- >out || fail
=1
176 compare
/dev
/null out || fail
=1