xref: /freebsd-src/usr.bin/wc/tests/wc_test.sh (revision 5c870e1b48948a283c963ecb88780e4e0406ac1e)
1dad64f0eSDag-Erling Smørgrav#
2dad64f0eSDag-Erling Smørgrav# Copyright (c) 2023 Klara, Inc.
3dad64f0eSDag-Erling Smørgrav#
4dad64f0eSDag-Erling Smørgrav# SPDX-License-Identifier: BSD-2-Clause
5dad64f0eSDag-Erling Smørgrav#
6dad64f0eSDag-Erling Smørgrav
7dad64f0eSDag-Erling Smørgrav#
8dad64f0eSDag-Erling Smørgrav# These tests need to run in a multibyte locale with non-localized
9dad64f0eSDag-Erling Smørgrav# error messages.
10dad64f0eSDag-Erling Smørgrav#
11dad64f0eSDag-Erling Smørgravexport LC_CTYPE=C.UTF-8
12dad64f0eSDag-Erling Smørgravexport LC_MESSAGES=C
13dad64f0eSDag-Erling Smørgrav
14dad64f0eSDag-Erling Smørgrav#
15*5c870e1bSDag-Erling Smørgrav# Size of wc's read buffer.
16*5c870e1bSDag-Erling Smørgrav#
17*5c870e1bSDag-Erling SmørgravMAXBSIZE=65536
18*5c870e1bSDag-Erling Smørgrav
19*5c870e1bSDag-Erling Smørgrav#
20dad64f0eSDag-Erling Smørgrav# Sample text containing multibyte characters
21dad64f0eSDag-Erling Smørgrav#
22dad64f0eSDag-Erling Smørgravtv="Der bode en underlig gråsprængt en
23dad64f0eSDag-Erling Smørgravpå den yderste nøgne ø; –
24dad64f0eSDag-Erling Smørgravhan gjorde visst intet menneske mén
25dad64f0eSDag-Erling Smørgravhverken på land eller sjø;
26dad64f0eSDag-Erling Smørgravdog stundom gnistred hans øjne stygt, –
27dad64f0eSDag-Erling Smørgravhelst mod uroligt vejr, –
28dad64f0eSDag-Erling Smørgravog da mente folk, at han var forrykt,
29dad64f0eSDag-Erling Smørgravog da var der få, som uden frykt
30dad64f0eSDag-Erling Smørgravkom Terje Vigen nær.
31dad64f0eSDag-Erling Smørgrav"
32dad64f0eSDag-Erling Smørgravtvl=10
33dad64f0eSDag-Erling Smørgravtvw=55
34dad64f0eSDag-Erling Smørgravtvc=300
35dad64f0eSDag-Erling Smørgravtvm=283
36dad64f0eSDag-Erling SmørgravtvcL=42
37dad64f0eSDag-Erling SmørgravtvmL=39
38dad64f0eSDag-Erling Smørgrav
39dad64f0eSDag-Erling Smørgrav#
40dad64f0eSDag-Erling Smørgrav# Run a series of tests using the same input file.  The first argument
41dad64f0eSDag-Erling Smørgrav# is the name of the file.  The next three are the expected line,
42dad64f0eSDag-Erling Smørgrav# word, and byte counts.  The optional fifth is the expected character
43dad64f0eSDag-Erling Smørgrav# count; if not provided, it is expected to be identical to the byte
44dad64f0eSDag-Erling Smørgrav# count.
45dad64f0eSDag-Erling Smørgrav#
46dad64f0eSDag-Erling Smørgravatf_check_wc() {
47dad64f0eSDag-Erling Smørgrav	local file="$1"
48dad64f0eSDag-Erling Smørgrav	local l="$2"
49dad64f0eSDag-Erling Smørgrav	local w="$3"
50dad64f0eSDag-Erling Smørgrav	local c="$4"
51dad64f0eSDag-Erling Smørgrav	local m="${5-$4}"
52dad64f0eSDag-Erling Smørgrav
53dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${l} +${w} +${c}\$" wc <"${file}"
54dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${l}\$" wc -l <"${file}"
55dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${w}\$" wc -w <"${file}"
56dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${c}\$" wc -c <"${file}"
57dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${m}\$" wc -m <"${file}"
58dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${l} +${w} +${c} ${file}\$" wc "$file"
59dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${l} ${file}\$" wc -l "$file"
60dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${w} ${file}\$" wc -w "$file"
61dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${c} ${file}\$" wc -c "$file"
62dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +${m} ${file}\$" wc -m "$file"
63dad64f0eSDag-Erling Smørgrav}
64dad64f0eSDag-Erling Smørgrav
65dad64f0eSDag-Erling Smørgravatf_test_case basic
66dad64f0eSDag-Erling Smørgravbasic_head()
67dad64f0eSDag-Erling Smørgrav{
68dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Basic test case"
69dad64f0eSDag-Erling Smørgrav}
70dad64f0eSDag-Erling Smørgravbasic_body()
71dad64f0eSDag-Erling Smørgrav{
72dad64f0eSDag-Erling Smørgrav	printf "a b\n" >foo
73dad64f0eSDag-Erling Smørgrav	atf_check_wc foo 1 2 4
74dad64f0eSDag-Erling Smørgrav}
75dad64f0eSDag-Erling Smørgrav
76dad64f0eSDag-Erling Smørgravatf_test_case blank
77dad64f0eSDag-Erling Smørgravblank_head()
78dad64f0eSDag-Erling Smørgrav{
79dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Input containing only blank lines"
80dad64f0eSDag-Erling Smørgrav}
81dad64f0eSDag-Erling Smørgravblank_body()
82dad64f0eSDag-Erling Smørgrav{
83dad64f0eSDag-Erling Smørgrav	printf "\n\n\n" >foo
84dad64f0eSDag-Erling Smørgrav	atf_check_wc foo 3 0 3
85dad64f0eSDag-Erling Smørgrav}
86dad64f0eSDag-Erling Smørgrav
87dad64f0eSDag-Erling Smørgravatf_test_case empty
88dad64f0eSDag-Erling Smørgravempty_head()
89dad64f0eSDag-Erling Smørgrav{
90dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Empty input"
91dad64f0eSDag-Erling Smørgrav}
92dad64f0eSDag-Erling Smørgravempty_body()
93dad64f0eSDag-Erling Smørgrav{
94dad64f0eSDag-Erling Smørgrav	printf "" >foo
95dad64f0eSDag-Erling Smørgrav	atf_check_wc foo 0 0 0
96dad64f0eSDag-Erling Smørgrav}
97dad64f0eSDag-Erling Smørgrav
98dad64f0eSDag-Erling Smørgravatf_test_case invalid
99dad64f0eSDag-Erling Smørgravinvalid_head()
100dad64f0eSDag-Erling Smørgrav{
101dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Invalid multibyte input"
102dad64f0eSDag-Erling Smørgrav}
103dad64f0eSDag-Erling Smørgravinvalid_body()
104dad64f0eSDag-Erling Smørgrav{
105dad64f0eSDag-Erling Smørgrav	printf "a\377b\n" >foo
106dad64f0eSDag-Erling Smørgrav	atf_check \
107dad64f0eSDag-Erling Smørgrav	    -e match:"Illegal byte sequence" \
108dad64f0eSDag-Erling Smørgrav	    -o match:"^ +4 foo$" \
109dad64f0eSDag-Erling Smørgrav	    wc -m foo
110dad64f0eSDag-Erling Smørgrav}
111dad64f0eSDag-Erling Smørgrav
112dad64f0eSDag-Erling Smørgravatf_test_case multiline
113dad64f0eSDag-Erling Smørgravmultiline_head()
114dad64f0eSDag-Erling Smørgrav{
115dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Multiline, multibyte input"
116dad64f0eSDag-Erling Smørgrav}
117dad64f0eSDag-Erling Smørgravmultiline_body()
118dad64f0eSDag-Erling Smørgrav{
119dad64f0eSDag-Erling Smørgrav	printf "%s\n" "$tv" >foo
120dad64f0eSDag-Erling Smørgrav	atf_check_wc foo $tvl $tvw $tvc $tvm
121dad64f0eSDag-Erling Smørgrav	# longest line in bytes
122dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +$tvc +$tvcL foo" wc -cL foo
123dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +$tvc +$tvcL" wc -cL <foo
124dad64f0eSDag-Erling Smørgrav	# longest line in characters
125dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +$tvm +$tvmL foo" wc -mL foo
126dad64f0eSDag-Erling Smørgrav	atf_check -o match:"^ +$tvm +$tvmL" wc -mL <foo
127dad64f0eSDag-Erling Smørgrav}
128dad64f0eSDag-Erling Smørgrav
129dad64f0eSDag-Erling Smørgravatf_test_case multiline_repeated
130dad64f0eSDag-Erling Smørgravmultiline_repeated_head()
131dad64f0eSDag-Erling Smørgrav{
132dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Multiline input exceeding the input buffer size"
133dad64f0eSDag-Erling Smørgrav}
134dad64f0eSDag-Erling Smørgravmultiline_repeated_body()
135dad64f0eSDag-Erling Smørgrav{
136dad64f0eSDag-Erling Smørgrav	local c=0
137dad64f0eSDag-Erling Smørgrav	while [ $c -lt 1000 ] ; do
138dad64f0eSDag-Erling Smørgrav		printf "%1\$s\n%1\$s\n%1\$s\n%1\$s\n%1\$s\n" "$tv"
139dad64f0eSDag-Erling Smørgrav		c=$((c+5))
140dad64f0eSDag-Erling Smørgrav	done >foo
141dad64f0eSDag-Erling Smørgrav	atf_check_wc foo $((tvl*c)) $((tvw*c)) $((tvc*c)) $((tvm*c))
142dad64f0eSDag-Erling Smørgrav}
143dad64f0eSDag-Erling Smørgrav
144*5c870e1bSDag-Erling Smørgravatf_test_case nul
145*5c870e1bSDag-Erling Smørgravnul_head()
146*5c870e1bSDag-Erling Smørgrav{
147*5c870e1bSDag-Erling Smørgrav	atf_set "descr" "Input containing NUL"
148*5c870e1bSDag-Erling Smørgrav}
149*5c870e1bSDag-Erling Smørgravnul_body()
150*5c870e1bSDag-Erling Smørgrav{
151*5c870e1bSDag-Erling Smørgrav	printf "a\0b\n" >foo
152*5c870e1bSDag-Erling Smørgrav	atf_check_wc foo 1 1 4
153*5c870e1bSDag-Erling Smørgrav}
154*5c870e1bSDag-Erling Smørgrav
155*5c870e1bSDag-Erling Smørgravatf_test_case poop
156*5c870e1bSDag-Erling Smørgravpoop_head()
157*5c870e1bSDag-Erling Smørgrav{
158*5c870e1bSDag-Erling Smørgrav	atf_set "descr" "Multibyte sequence across buffer boundary"
159*5c870e1bSDag-Erling Smørgrav}
160*5c870e1bSDag-Erling Smørgravpoop_body()
161*5c870e1bSDag-Erling Smørgrav{
162*5c870e1bSDag-Erling Smørgrav	local l=0 w=0 c=0 m=0
163*5c870e1bSDag-Erling Smørgrav	# The code below produces a stream of 4-byte UTF-8 sequences
164*5c870e1bSDag-Erling Smørgrav	# aligned on 5-byte boundaries, ensuring that the first full
165*5c870e1bSDag-Erling Smørgrav	# read of length MAXBSIZE will end in a partial sequence —
166*5c870e1bSDag-Erling Smørgrav	# unless MAXBSIZE is a multiple of 5 (not possible since it's
167*5c870e1bSDag-Erling Smørgrav	# a power of 2) or one less than a multiple of 5 (e.g. 2^18 =
168*5c870e1bSDag-Erling Smørgrav	# 262,144 = (52429 * 5) - 1) in which case we prepend a single
169*5c870e1bSDag-Erling Smørgrav	# newline to push our sequence out of phase.
170*5c870e1bSDag-Erling Smørgrav	atf_check_not_equal 0 $((MAXBSIZE % 5))
171*5c870e1bSDag-Erling Smørgrav	:>foo
172*5c870e1bSDag-Erling Smørgrav	if [ $((MAXBSIZE % 5)) -eq 4 ] ; then
173*5c870e1bSDag-Erling Smørgrav		printf "\n"
174*5c870e1bSDag-Erling Smørgrav		l=$((l + 1))
175*5c870e1bSDag-Erling Smørgrav		c=$((c + 1))
176*5c870e1bSDag-Erling Smørgrav		m=$((m + 1))
177*5c870e1bSDag-Erling Smørgrav	fi >>foo
178*5c870e1bSDag-Erling Smørgrav	while [ $c -le $MAXBSIZE ] ; do
179*5c870e1bSDag-Erling Smørgrav		printf "��.��.��.��.��.��.��.��.��.��.��.��.��.��.��.��\n"
180*5c870e1bSDag-Erling Smørgrav		l=$((l + 1))
181*5c870e1bSDag-Erling Smørgrav		w=$((w + 1))
182*5c870e1bSDag-Erling Smørgrav		c=$((c + 80)) # 80 bytes
183*5c870e1bSDag-Erling Smørgrav		m=$((m + 32)) # 32 multibyte characters
184*5c870e1bSDag-Erling Smørgrav	done >>foo
185*5c870e1bSDag-Erling Smørgrav	atf_check_wc foo $l $w $c $m
186*5c870e1bSDag-Erling Smørgrav}
187*5c870e1bSDag-Erling Smørgrav
188dad64f0eSDag-Erling Smørgravatf_test_case total
189dad64f0eSDag-Erling Smørgravtotal_head()
190dad64f0eSDag-Erling Smørgrav{
191dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Multiple inputs"
192dad64f0eSDag-Erling Smørgrav}
193dad64f0eSDag-Erling Smørgravtotal_body()
194dad64f0eSDag-Erling Smørgrav{
195dad64f0eSDag-Erling Smørgrav	printf "%s\n" "$tv" >foo
196dad64f0eSDag-Erling Smørgrav	printf "%s\n" "$tv" >bar
197dad64f0eSDag-Erling Smørgrav	atf_check \
198dad64f0eSDag-Erling Smørgrav	    -o match:"^ +$((tvl*2)) +$((tvw*2)) +$((tvc*2)) total$" \
199dad64f0eSDag-Erling Smørgrav	    wc foo bar
200dad64f0eSDag-Erling Smørgrav}
201dad64f0eSDag-Erling Smørgrav
202dad64f0eSDag-Erling Smørgravatf_test_case unterminated
203dad64f0eSDag-Erling Smørgravunterminated_head()
204dad64f0eSDag-Erling Smørgrav{
205dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Input not ending in newline"
206dad64f0eSDag-Erling Smørgrav}
207dad64f0eSDag-Erling Smørgravunterminated_body()
208dad64f0eSDag-Erling Smørgrav{
209dad64f0eSDag-Erling Smørgrav	printf "a b" >foo
210dad64f0eSDag-Erling Smørgrav	atf_check_wc foo 0 2 3
211dad64f0eSDag-Erling Smørgrav}
212dad64f0eSDag-Erling Smørgrav
213dad64f0eSDag-Erling Smørgravatf_test_case usage
214dad64f0eSDag-Erling Smørgravusage_head()
215dad64f0eSDag-Erling Smørgrav{
216dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Trigger usage message"
217dad64f0eSDag-Erling Smørgrav}
218dad64f0eSDag-Erling Smørgravusage_body()
219dad64f0eSDag-Erling Smørgrav{
220dad64f0eSDag-Erling Smørgrav	atf_check -s exit:1 -e match:"usage: wc" wc -\?
221dad64f0eSDag-Erling Smørgrav}
222dad64f0eSDag-Erling Smørgrav
223dad64f0eSDag-Erling Smørgravatf_test_case whitespace
224dad64f0eSDag-Erling Smørgravwhitespace_head()
225dad64f0eSDag-Erling Smørgrav{
226dad64f0eSDag-Erling Smørgrav	atf_set "descr" "Input containing only whitespace and newlines"
227dad64f0eSDag-Erling Smørgrav}
228dad64f0eSDag-Erling Smørgravwhitespace_body()
229dad64f0eSDag-Erling Smørgrav{
230dad64f0eSDag-Erling Smørgrav	printf "\n \n\t\n" >foo
231dad64f0eSDag-Erling Smørgrav	atf_check_wc foo 3 0 5
232dad64f0eSDag-Erling Smørgrav}
233dad64f0eSDag-Erling Smørgrav
234dad64f0eSDag-Erling Smørgravatf_init_test_cases()
235dad64f0eSDag-Erling Smørgrav{
236dad64f0eSDag-Erling Smørgrav	atf_add_test_case basic
237dad64f0eSDag-Erling Smørgrav	atf_add_test_case blank
238dad64f0eSDag-Erling Smørgrav	atf_add_test_case empty
239dad64f0eSDag-Erling Smørgrav	atf_add_test_case invalid
240dad64f0eSDag-Erling Smørgrav	atf_add_test_case multiline
241dad64f0eSDag-Erling Smørgrav	atf_add_test_case multiline_repeated
242*5c870e1bSDag-Erling Smørgrav	atf_add_test_case nul
243*5c870e1bSDag-Erling Smørgrav	atf_add_test_case poop
244dad64f0eSDag-Erling Smørgrav	atf_add_test_case total
245dad64f0eSDag-Erling Smørgrav	atf_add_test_case unterminated
246dad64f0eSDag-Erling Smørgrav	atf_add_test_case usage
247dad64f0eSDag-Erling Smørgrav	atf_add_test_case whitespace
248dad64f0eSDag-Erling Smørgrav}
249