tests: add test for locale decimal processing
[coreutils.git] / tests / misc / shuf.sh
blobbbc54a9d2c70f546d76b06f0b54f7ab6b44e62c2
1 #!/bin/sh
2 # Ensure that shuf randomizes its input.
4 # Copyright (C) 2006-2019 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
20 print_ver_ shuf
21 getlimits_
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.
33 sort -n out > out1
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; }
39 sort -n out > out1
40 compare in out1 || { fail=1; echo "not a permutation" 1>&2; }
42 # Exercise shuf's -e option.
43 t=$(shuf -e a b c d e | sort | fmt)
44 test "$t" = 'a b c d e' || { fail=1; echo "not a permutation" 1>&2; }
46 # coreutils-8.22 dumps core.
47 shuf -er
48 test $? -eq 1 || fail=1
50 # coreutils-8.22 and 8.23 dump core
51 # with a single redundant operand with --input-range
52 shuf -i0-0 1
53 test $? -eq 1 || fail=1
55 # Before coreutils-6.3, this would infloop.
56 # "seq 1860" produces 8193 (8K + 1) bytes of output.
57 seq 1860 | shuf > /dev/null || fail=1
59 # coreutils-6.12 and earlier would output a newline terminator, not \0.
60 shuf --zero-terminated -i 1-1 > out || fail=1
61 printf '1\0' > exp || framework_failure_
62 cmp out exp || { fail=1; echo "missing NUL terminator?" 1>&2; }
64 # Ensure shuf -n operates efficiently for small n. Before coreutils-8.13
65 # this would try to allocate $SIZE_MAX * sizeof(size_t)
66 timeout 10 shuf -i1-$SIZE_MAX -n2 >/dev/null ||
67 { fail=1; echo "couldn't get a small subset" >&2; }
69 # Ensure shuf -n0 doesn't read any input or open specified files
70 touch unreadable || framework_failure_
71 chmod 0 unreadable || framework_failure_
72 if ! test -r unreadable; then
73 shuf -n0 unreadable || fail=1
74 { shuf -n1 unreadable || test $? -ne 1; } && fail=1
77 # Multiple -n is accepted, should use the smallest value
78 shuf -n10 -i0-9 -n3 -n20 > exp || framework_failure_
79 c=$(wc -l < exp) || framework_failure_
80 test "$c" -eq 3 || { fail=1; echo "Multiple -n failed">&2 ; }
82 # Test error conditions
84 # -i and -e must not be used together
85 : | { shuf -i0-9 -e A B || test $? -ne 1; } &&
86 { fail=1; echo "shuf did not detect erroneous -e and -i usage.">&2 ; }
87 # Test invalid value for -n
88 : | { shuf -nA || test $? -ne 1; } &&
89 { fail=1; echo "shuf did not detect erroneous -n usage.">&2 ; }
90 # Test multiple -i
91 { shuf -i0-9 -n10 -i8-90 || test $? -ne 1; } &&
92 { fail=1; echo "shuf did not detect multiple -i usage.">&2 ; }
93 # Test invalid range
94 for ARG in '1' 'A' '1-' '1-A'; do
95 { shuf -i$ARG || test $? -ne 1; } &&
96 { fail=1; echo "shuf did not detect erroneous -i$ARG usage.">&2 ; }
97 done
99 # multiple -o are forbidden
100 { shuf -i0-9 -o A -o B || test $? -ne 1; } &&
101 { fail=1; echo "shuf did not detect erroneous multiple -o usage.">&2 ; }
102 # multiple random-sources are forbidden
103 { shuf -i0-9 --random-source A --random-source B || test $? -ne 1; } &&
104 { fail=1; echo "shuf did not detect multiple --random-source usage.">&2 ; }
106 # Test --repeat option
108 # --repeat without count should return an indefinite number of lines
109 shuf --rep -i 0-10 | head -n 1000 > exp || framework_failure_
110 c=$(wc -l < exp) || framework_failure_
111 test "$c" -eq 1000 \
112 || { fail=1; echo "--repeat does not repeat indefinitely">&2 ; }
114 # --repeat can output more values than the input range
115 shuf --rep -i0-9 -n1000 > exp || framework_failure_
116 c=$(wc -l < exp) || framework_failure_
117 test "$c" -eq 1000 || { fail=1; echo "--repeat with --count failed">&2 ; }
119 # Check output values (this is not bullet-proof, but drawing 1000 values
120 # between 0 and 9 should produce all values, unless there's a bug in shuf
121 # or a very poor random source, or extremely bad luck)
122 c=$(sort -nu exp | paste -s -d ' ') || framework_failure_
123 test "$c" = "0 1 2 3 4 5 6 7 8 9" ||
124 { fail=1; echo "--repeat produced bad output">&2 ; }
126 # check --repeat with non-zero low value
127 shuf --rep -i222-233 -n2000 > exp || framework_failure_
128 c=$(sort -nu exp | paste -s -d ' ') || framework_failure_
129 test "$c" = "222 223 224 225 226 227 228 229 230 231 232 233" ||
130 { fail=1; echo "--repeat produced bad output with non-zero low">&2 ; }
132 # --repeat,-i,count=0 should not fail and produce no output
133 shuf --rep -i0-9 -n0 > exp || framework_failure_
134 # file size should be zero (no output from shuf)
135 test \! -s exp ||
136 { fail=1; echo "--repeat,-i0-9,-n0 produced bad output">&2 ; }
138 # --repeat with -e, without count, should repeat indefinitely
139 shuf --rep -e A B C D | head -n 1000 > exp || framework_failure_
140 c=$(wc -l < exp) || framework_failure_
141 test "$c" -eq 1000 ||
142 { fail=1; echo "--repeat,-e does not repeat indefinitely">&2 ; }
144 # --repeat with STDIN, without count, should repeat indefinitely
145 printf "A\nB\nC\nD\nE\n" | shuf --rep | head -n 1000 > exp || framework_failure_
146 c=$(wc -l < exp) || framework_failure_
147 test "$c" -eq 1000 ||
148 { fail=1; echo "--repeat,STDIN does not repeat indefinitely">&2 ; }
150 # --repeat with STDIN,count - can return move values than input lines
151 printf "A\nB\nC\nD\nE\n" | shuf --rep -n2000 > exp || framework_failure_
152 c=$(wc -l < exp) || framework_failure_
153 test "$c" -eq 2000 ||
154 { fail=1; echo "--repeat,STDIN,count failed">&2 ; }
156 # Check output values (this is not bullet-proof, but drawing 2000 values
157 # between A and E should produce all values, unless there's a bug in shuf
158 # or a very poor random source, or extremely bad luck)
159 c=$(sort -u exp | paste -s -d ' ') || framework_failure_
160 test "$c" = "A B C D E" ||
161 { fail=1; echo "--repeat,STDIN,count produced bad output">&2 ; }
163 # --repeat,stdin,count=0 should not fail and produce no output
164 printf "A\nB\nC\nD\nE\n" | shuf --rep -n0 > exp || framework_failure_
165 # file size should be zero (no output from shuf)
166 test \! -s exp ||
167 { fail=1; echo "--repeat,STDIN,-n0 produced bad output">&2 ; }
169 # shuf 8.25 mishandles input if stdin is closed, due to glibc bug#15589.
170 # See coreutils bug#25029.
171 shuf /dev/null <&- >out || fail=1
172 compare /dev/null out || fail=1
174 Exit $fail