xref: /freebsd/usr.bin/tail/tests/tail_test.sh (revision a9c72543d287afa8dd30bec0f49873e88057c192)
1# SPDX-License-Identifier: BSD-2-Clause
2#
3# Copyright (c) 2016 Alan Somers
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1. Redistributions of source code must retain the above copyright
9#    notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11#    notice, this list of conditions and the following disclaimer in the
12#    documentation and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24# SUCH DAMAGE.
25#
26
27atf_test_case empty_r
28empty_r_head()
29{
30	atf_set "descr" "Reverse an empty file"
31}
32empty_r_body()
33{
34	touch infile expectfile
35	tail -r infile > outfile
36	tail -r < infile > outpipe
37	atf_check cmp expectfile outfile
38	atf_check cmp expectfile outpipe
39}
40
41atf_test_case file_r
42file_r_head()
43{
44	atf_set "descr" "Reverse a file"
45}
46file_r_body()
47{
48	cat > infile <<HERE
49This is the first line
50This is the second line
51This is the third line
52HERE
53	cat > expectfile << HERE
54This is the third line
55This is the second line
56This is the first line
57HERE
58	tail -r infile > outfile
59	tail -r < infile > outpipe
60	atf_check cmp expectfile outfile
61	atf_check cmp expectfile outpipe
62}
63
64atf_test_case file_rn2
65file_rn2_head()
66{
67	atf_set "descr" "Reverse the last two lines of a file"
68}
69file_rn2_body()
70{
71	cat > infile <<HERE
72This is the first line
73This is the second line
74This is the third line
75HERE
76	cat > expectfile << HERE
77This is the third line
78This is the second line
79HERE
80	tail -rn2 infile > outfile
81	tail -rn2 < infile > outpipe
82	atf_check cmp expectfile outfile
83	atf_check cmp expectfile outpipe
84}
85
86# Regression test for PR 222671
87# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222671
88atf_test_case pipe_leading_newline_r
89pipe_leading_newline_r_head()
90{
91	atf_set "descr" "Reverse a pipe whose first character is a newline"
92}
93pipe_leading_newline_r_body()
94{
95	cat > expectfile << HERE
963
972
981
99
100HERE
101	printf '\n1\n2\n3\n' | tail -r > outfile
102	printf '\n1\n2\n3\n' | tail -r > outpipe
103	atf_check cmp expectfile outfile
104	atf_check cmp expectfile outpipe
105}
106
107atf_test_case file_rc28
108file_rc28_head()
109{
110	atf_set "descr" "Reverse a file and display the last 28 characters"
111}
112file_rc28_body()
113{
114	cat > infile <<HERE
115This is the first line
116This is the second line
117This is the third line
118HERE
119	cat > expectfile << HERE
120This is the third line
121line
122HERE
123	tail -rc28 infile > outfile
124	tail -rc28 < infile > outpipe
125	atf_check cmp expectfile outfile
126	atf_check cmp expectfile outpipe
127}
128
129atf_test_case file_rc28
130file_rc28_head()
131{
132	atf_set "descr" "Reverse a file and display the last 28 characters"
133}
134file_rc28_body()
135{
136	cat > infile <<HERE
137This is the first line
138This is the second line
139This is the third line
140HERE
141	cat > expectfile << HERE
142This is the third line
143line
144HERE
145	tail -rc28 infile > outfile
146	tail -rc28 < infile > outpipe
147	atf_check cmp expectfile outfile
148	atf_check cmp expectfile outpipe
149}
150
151atf_test_case longfile_r
152longfile_r_head()
153{
154	atf_set "descr" "Reverse a long file"
155}
156longfile_r_body()
157{
158	jot -w "%0511d" 1030 0 > infile
159	jot -w "%0511d" 1030 1029 0 -1 > expectfile
160	tail -r infile > outfile
161	tail -r < infile > outpipe
162	atf_check cmp expectfile outfile
163	atf_check cmp expectfile outpipe
164}
165
166atf_test_case longfile_r_enomem
167longfile_r_enomem_head()
168{
169	atf_set "descr" "Reverse a file that's too long to store in RAM"
170}
171longfile_r_enomem_body()
172{
173	# When we reverse a file that's too long for RAM, tail should drop the
174	# first part and just print what it can.  We'll check that the last
175	# part is ok
176	{
177		ulimit -v 32768 || atf_skip "Can't adjust ulimit"
178		jot -w "%01023d" 32768 0 | tail -r > outfile ;
179	}
180	if [ "$?" -ne 1 ]; then
181		atf_skip "Didn't get ENOMEM.  Adjust test parameters"
182	fi
183	# We don't know how much of the input we dropped.  So just check that
184	# the first ten lines of tail's output are the same as the last ten of
185	# the input
186	jot -w "%01023d" 10 32767 0 -1 > expectfile
187	head -n 10 outfile > outtrunc
188	diff expectfile outtrunc
189	atf_check cmp expectfile outtrunc
190}
191
192atf_test_case longfile_r_longlines
193longfile_r_longlines_head()
194{
195	atf_set "descr" "Reverse a long file with extremely long lines"
196}
197longfile_r_longlines_body()
198{
199	jot -s " " -w "%07d" 18000 0 > infile
200	jot -s " " -w "%07d" 18000 18000 >> infile
201	jot -s " " -w "%07d" 18000 36000 >> infile
202	jot -s " " -w "%07d" 18000 36000 > expectfile
203	jot -s " " -w "%07d" 18000 18000 >> expectfile
204	jot -s " " -w "%07d" 18000 0 >> expectfile
205	tail -r infile > outfile
206	tail -r < infile > outpipe
207	atf_check cmp expectfile outfile
208	atf_check cmp expectfile outpipe
209}
210
211atf_test_case longfile_rc135782
212longfile_rc135782_head()
213{
214	atf_set "descr" "Reverse a long file and print the last 135,782 bytes"
215}
216longfile_rc135782_body()
217{
218	jot -w "%063d" 9000 0 > infile
219	jot -w "%063d" 2121 8999 0 -1 > expectfile
220	echo "0000000000000000000000000000000006878" >> expectfile
221	tail -rc135782 infile > outfile
222	tail -rc135782 < infile > outpipe
223	atf_check cmp expectfile outfile
224	atf_check cmp expectfile outpipe
225}
226
227atf_test_case longfile_rc145782_longlines
228longfile_rc145782_longlines_head()
229{
230	atf_set "descr" "Reverse a long file with extremely long lines and print the last 145,782 bytes"
231}
232longfile_rc145782_longlines_body()
233{
234	jot -s " " -w "%07d" 18000 0 > infile
235	jot -s " " -w "%07d" 18000 18000 >> infile
236	jot -s " " -w "%07d" 18000 36000 >> infile
237	jot -s " " -w "%07d" 18000 36000 > expectfile
238	echo -n "35777 " >> expectfile
239	jot -s " " -w "%07d" 222 35778 >> expectfile
240	tail -rc145782 infile > outfile
241	tail -rc145782 < infile > outpipe
242	atf_check cmp expectfile outfile
243	atf_check cmp expectfile outpipe
244}
245
246atf_test_case longfile_rn2500
247longfile_rn2500_head()
248{
249	atf_set "descr" "Reverse a long file and print the last 2,500 lines"
250}
251longfile_rn2500_body()
252{
253	jot -w "%063d" 9000 0 > infile
254	jot -w "%063d" 2500 8999 0 -1 > expectfile
255	tail -rn2500 infile > outfile
256	tail -rn2500 < infile > outpipe
257	atf_check cmp expectfile outfile
258	atf_check cmp expectfile outpipe
259}
260
261atf_test_case broken_pipe
262broken_pipe_head()
263{
264	atf_set "descr" "Do not print bogus errno based output on short writes"
265}
266broken_pipe_body()
267{
268	atf_check -o save:ints seq -f '%128g' 1 1000
269	atf_check -s ignore \
270	    -e "inline:tail: stdout\nexit code: 1\n" \
271	    -x '(tail -n 856 ints; echo exit code: $? >&2) | sleep 2'
272}
273
274atf_test_case stdin
275stdin_head()
276{
277	atf_set "descr" "Check basic operations on standard input"
278}
279stdin_body()
280{
281	seq 1 5 > infile
282	seq 1 5 > expectfile
283	seq 5 1 > expectfile_r
284
285	tail < infile > outfile
286	tail -r < infile > outfile_r
287
288	atf_check cmp expectfile outfile
289	atf_check cmp expectfile_r outfile_r
290}
291
292atf_test_case follow
293follow_head()
294{
295	atf_set "descr" "Basic regression test for -f"
296}
297follow_body()
298{
299	local pid
300
301	seq 1 5 > expectfile
302	seq 1 3 > infile
303	tail -f infile > outfile &
304	pid=$!
305	sleep 0.1
306	seq 4 5 >> infile
307	sleep 0.1
308	atf_check cmp expectfile outfile
309	atf_check kill $pid
310}
311
312atf_test_case follow_stdin
313follow_stdin_head()
314{
315	atf_set "descr" "Verify that -f works with files piped to standard input"
316}
317follow_stdin_body()
318{
319	local pid
320
321	seq 1 5 > expectfile
322	seq 1 3 > infile
323	tail -f < infile > outfile &
324	pid=$!
325	sleep 0.1
326	seq 4 5 >> infile
327	sleep 0.1
328	atf_check cmp expectfile outfile
329	atf_check kill $pid
330}
331
332atf_test_case follow_create
333follow_create_head()
334{
335	atf_set "descr" "Verify that -F works when a file is created"
336}
337follow_create_body()
338{
339	local pid
340
341	rm -f infile
342	tail -F infile > outfile &
343	pid=$!
344	sleep 0.1
345	seq 1 5 >infile
346	sleep 2
347	atf_check cmp infile outfile
348	atf_check kill $pid
349}
350
351atf_test_case follow_rename
352follow_rename_head()
353{
354	atf_set "descr" "Verify that -F works when a file is replaced"
355}
356follow_rename_body()
357{
358	local pid
359
360	seq 1 5 > expectfile
361	seq 1 3 > infile
362	tail -F infile > outfile &
363	pid=$!
364	sleep 0.1
365	seq 4 5 > infile_new
366	atf_check mv infile infile_old
367	atf_check mv infile_new infile
368	# tail -F polls for a new file every 1s.
369	sleep 2
370	atf_check cmp expectfile outfile
371	atf_check kill $pid
372}
373
374atf_test_case silent_header
375silent_header_head() {
376	atf_set "descr" "Test tail(1)'s silent header feature"
377}
378silent_header_body() {
379	jot 11 1 11 > file1
380	jot 11 2 12 > file2
381	jot 10 2 11 > expectfile
382	jot 10 3 12 >> expectfile
383	tail -q file1 file2 > outfile
384	atf_check cmp outfile expectfile
385}
386
387atf_test_case verbose_header
388verbose_header_head() {
389	atf_set "descr" "Test tail(1)'s verbose header feature"
390}
391verbose_header_body() {
392	jot 11 1 11 > file1
393	echo '==> file1 <==' > expectfile
394	jot 10 2 11 >> expectfile
395	tail -v file1 > outfile
396	atf_check cmp outfile expectfile
397}
398
399atf_test_case si_number
400si_number_head() {
401	atf_set "descr" "Test tail(1)'s SI number feature"
402}
403si_number_body() {
404	jot -b aaaaaaa 129 > file1
405	jot -b aaaaaaa 128 > expectfile
406	tail -c 1k file1 > outfile
407	atf_check cmp outfile expectfile
408	jot 1025 1 1025 > file1
409	jot 1024 2 1025 > expectfile
410	tail -n 1k file1 > outfile
411	atf_check cmp outfile expectfile
412}
413
414atf_test_case no_lf_at_eof
415no_lf_at_eof_head()
416{
417	atf_set "descr" "File does not end in newline"
418}
419no_lf_at_eof_body()
420{
421	printf "a\nb\nc" >infile
422	atf_check -o inline:"c" tail -1 infile
423	atf_check -o inline:"b\nc" tail -2 infile
424	atf_check -o inline:"a\nb\nc" tail -3 infile
425	atf_check -o inline:"a\nb\nc" tail -4 infile
426}
427
428atf_test_case tail_b
429tail_b_head()
430{
431	atf_set "descr" "Test -b option"
432}
433tail_b_body()
434{
435	(jot -b a 256 ; jot -b b 256 ; jot -b c 256) >infile
436	(jot -b b 256 ; jot -b c 256) >outfile
437	# infile is 3 blocks long, outfile contains the last two
438	atf_check -o file:outfile tail -b +2 infile # start at the 2nd block
439	atf_check -o file:outfile tail -b -2 infile # 2 blocks from the end
440	atf_check -o file:outfile tail -b  2 infile # 2 blocks from the end
441}
442
443atf_test_case tail_c
444tail_c_head()
445{
446	atf_set "descr" "Test -c option"
447}
448tail_c_body()
449{
450	(jot -b a 256 ; jot -b b 256 ; jot -b c 256) >infile
451	(jot -b b 256 ; jot -b c 256) >outfile
452	# infile is 1536 bytes long, outfile contains the last 1024
453	atf_check -o file:outfile tail -c  +513 infile # start at the 513th byte
454	atf_check -o file:outfile tail -c -1024 infile # 1024 bytes from the end
455	atf_check -o file:outfile tail -c  1024 infile # 1024 bytes from the end
456}
457
458atf_test_case tail_n
459tail_n_head()
460{
461	atf_set "descr" "Test -n option"
462}
463tail_n_body()
464{
465	(jot -b a 256 ; jot -b b 256 ; jot -b c 256) >infile
466	(jot -b b 256 ; jot -b c 256) >outfile
467	# infile is 768 lines long, outfile contains the last 512
468	atf_check -o file:outfile tail -n +257 infile # start at the 257th line
469	atf_check -o file:outfile tail -n -512 infile # 512 lines from the end
470	atf_check -o file:outfile tail -n  512 infile # 512 lines from the end
471}
472
473atf_init_test_cases()
474{
475	atf_add_test_case empty_r
476	atf_add_test_case file_r
477	atf_add_test_case file_rc28
478	atf_add_test_case file_rn2
479	atf_add_test_case pipe_leading_newline_r
480	# The longfile tests are designed to exercise behavior in r_buf(),
481	# which operates on 128KB blocks
482	atf_add_test_case longfile_r
483	atf_add_test_case longfile_r_enomem
484	atf_add_test_case longfile_r_longlines
485	atf_add_test_case longfile_rc135782
486	atf_add_test_case longfile_rc145782_longlines
487	atf_add_test_case longfile_rn2500
488	atf_add_test_case broken_pipe
489	atf_add_test_case stdin
490	atf_add_test_case follow
491	atf_add_test_case follow_stdin
492	atf_add_test_case follow_create
493	atf_add_test_case follow_rename
494	atf_add_test_case silent_header
495	atf_add_test_case verbose_header
496	atf_add_test_case si_number
497	atf_add_test_case no_lf_at_eof
498	atf_add_test_case tail_b
499	atf_add_test_case tail_c
500	atf_add_test_case tail_n
501}
502