xref: /freebsd/bin/ls/tests/ls_tests.sh (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1#
2# Copyright 2015 EMC Corp.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# * Redistributions of source code must retain the above copyright
10#   notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above copyright
12#   notice, this list of conditions and the following disclaimer in the
13#   documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# $FreeBSD$
28#
29
30create_test_dir()
31{
32	[ -z "$ATF_TMPDIR" ] || return 0
33
34	export ATF_TMPDIR=$(pwd)
35
36	# XXX: need to nest this because of how kyua creates $TMPDIR; otherwise
37	# it will run into EPERM issues later
38	TEST_INPUTS_DIR="${ATF_TMPDIR}/test/inputs"
39
40	atf_check -e empty -s exit:0 mkdir -m 0777 -p $TEST_INPUTS_DIR
41	cd $TEST_INPUTS_DIR
42}
43
44create_test_inputs()
45{
46	create_test_dir
47
48	atf_check -e empty -s exit:0 mkdir -m 0755 -p a/b/1
49	atf_check -e empty -s exit:0 ln -s a/b c
50	atf_check -e empty -s exit:0 touch d
51	atf_check -e empty -s exit:0 ln d e
52	atf_check -e empty -s exit:0 touch .f
53	atf_check -e empty -s exit:0 mkdir .g
54	atf_check -e empty -s exit:0 mkfifo h
55	atf_check -e ignore -s exit:0 dd if=/dev/zero of=i count=1000 bs=1
56	atf_check -e empty -s exit:0 touch klmn
57	atf_check -e empty -s exit:0 touch opqr
58	atf_check -e empty -s exit:0 touch stuv
59	atf_check -e empty -s exit:0 install -m 0755 /dev/null wxyz
60	atf_check -e empty -s exit:0 touch 0b00000001
61	atf_check -e empty -s exit:0 touch 0b00000010
62	atf_check -e empty -s exit:0 touch 0b00000011
63	atf_check -e empty -s exit:0 touch 0b00000100
64	atf_check -e empty -s exit:0 touch 0b00000101
65	atf_check -e empty -s exit:0 touch 0b00000110
66	atf_check -e empty -s exit:0 touch 0b00000111
67	atf_check -e empty -s exit:0 touch 0b00001000
68	atf_check -e empty -s exit:0 touch 0b00001001
69	atf_check -e empty -s exit:0 touch 0b00001010
70	atf_check -e empty -s exit:0 touch 0b00001011
71	atf_check -e empty -s exit:0 touch 0b00001100
72	atf_check -e empty -s exit:0 touch 0b00001101
73	atf_check -e empty -s exit:0 touch 0b00001110
74	atf_check -e empty -s exit:0 touch 0b00001111
75}
76
77KB=1024
78MB=$(( 1024 * $KB ))
79GB=$(( 1024 * $MB ))
80TB=$(( 1024 * $GB ))
81PB=$(( 1024 * $TB ))
82
83create_test_inputs2()
84{
85	create_test_dir
86
87	for filesize in 1 512 $(( 2 * $KB )) $(( 10 * $KB )) $(( 512 * $KB )); \
88	do
89		atf_check -e ignore -o empty -s exit:0 \
90		    dd if=/dev/zero of=${filesize}.file bs=1 \
91		    count=1 oseek=${filesize} conv=sparse
92		files="${files} ${filesize}.file"
93	done
94
95	for filesize in $MB $GB $TB; do
96		atf_check -e ignore -o empty -s exit:0 \
97		    dd if=/dev/zero of=${filesize}.file bs=$MB \
98		    count=1 oseek=$(( $filesize / $MB )) conv=sparse
99		files="${files} ${filesize}.file"
100	done
101}
102
103atf_test_case A_flag
104A_flag_head()
105{
106	atf_set "descr" "Verify -A support with unprivileged users"
107}
108
109A_flag_body()
110{
111	create_test_dir
112
113	atf_check -e empty -o empty -s exit:0 ls -A
114
115	create_test_inputs
116
117	WITH_A=$PWD/../with_A.out
118	WITHOUT_A=$PWD/../without_A.out
119
120	atf_check -e empty -o save:$WITH_A -s exit:0 ls -A
121	atf_check -e empty -o save:$WITHOUT_A -s exit:0 ls
122
123	echo "-A usage"
124	cat $WITH_A
125	echo "No -A usage"
126	cat $WITHOUT_A
127
128	for dot_path in '\.f' '\.g'; do
129		atf_check -e empty -o not-empty -s exit:0 grep "${dot_path}" \
130		    $WITH_A
131		atf_check -e empty -o empty -s not-exit:0 grep "${dot_path}" \
132		    $WITHOUT_A
133	done
134}
135
136atf_test_case A_flag_implied_when_root
137A_flag_implied_when_root_head()
138{
139	atf_set "descr" "Verify that -A is implied for root"
140	atf_set "require.user" "root"
141}
142
143A_flag_implied_when_root_body()
144{
145	create_test_dir
146
147	atf_check -e empty -o empty -s exit:0 ls -A
148
149	create_test_inputs
150
151	WITH_EXPLICIT=$PWD/../with_explicit_A.out
152	WITH_IMPLIED=$PWD/../with_implied_A.out
153
154	atf_check -e empty -o save:$WITH_EXPLICIT -s exit:0 ls -A
155	atf_check -e empty -o save:$WITH_IMPLIED -s exit:0 ls
156
157	echo "Explicit -A usage"
158	cat $WITH_EXPLICIT
159	echo "Implicit -A usage"
160	cat $WITH_IMPLIED
161
162	atf_check_equal "$(cat $WITH_EXPLICIT)" "$(cat $WITH_IMPLIED)"
163}
164
165atf_test_case B_flag
166B_flag_head()
167{
168	atf_set "descr" "Verify that the output from ls -B prints out non-printable characters"
169}
170
171B_flag_body()
172{
173	atf_check -e empty -o empty -s exit:0 touch "$(printf "y\013z")"
174	atf_check -e empty -o match:'y\\013z' -s exit:0 ls -B
175}
176
177atf_test_case C_flag
178C_flag_head()
179{
180	atf_set "descr" "Verify that the output from ls -C is multi-column, sorted down"
181}
182
183print_index()
184{
185	local i=1
186	local wanted_index=$1; shift
187
188	while [ $i -le $wanted_index ]; do
189		if [ $i -eq $wanted_index ]; then
190			echo $1
191			return
192		fi
193		shift
194		: $(( i += 1 ))
195	done
196}
197
198C_flag_body()
199{
200	create_test_inputs
201
202	WITH_C=$PWD/../with_C.out
203
204	export COLUMNS=40
205	atf_check -e empty -o save:$WITH_C -s exit:0 ls -C
206
207	echo "With -C usage"
208	cat $WITH_C
209
210	paths=$(find -s . -mindepth 1 -maxdepth 1 \! -name '.*' -exec basename {} \; )
211	set -- $paths
212	num_paths=$#
213	num_columns=2
214
215	max_num_paths_per_column=$(( $(( $num_paths + 1 )) / $num_columns ))
216
217	local i=1
218	while [ $i -le $max_num_paths_per_column ]; do
219		column_1=$(print_index $i $paths)
220		column_2=$(print_index $(( $i + $max_num_paths_per_column )) $paths)
221		#echo "paths[$(( $i + $max_num_paths_per_column ))] = $column_2"
222		expected_expr="$column_1"
223		if [ -n "$column_2" ]; then
224			expected_expr="$expected_expr[[:space:]]+$column_2"
225		fi
226		atf_check -e ignore -o not-empty -s exit:0 \
227		    egrep "$expected_expr" $WITH_C
228		: $(( i += 1 ))
229	done
230}
231
232atf_test_case D_flag
233D_flag_head()
234{
235	atf_set "descr" "Verify that the output from ls -D modifies the time format used with ls -l"
236}
237
238D_flag_body()
239{
240	atf_check -e empty -o empty -s exit:0 touch a.file
241	atf_check -e empty -o match:"$(stat -f '%c[[:space:]]+%N' a.file)" \
242	    -s exit:0 ls -lD '%s'
243}
244
245atf_test_case F_flag
246F_flag_head()
247{
248	atf_set "descr" "Verify that the output from ls -F prints out appropriate symbols after files"
249}
250
251F_flag_body()
252{
253	create_test_inputs
254
255	atf_check -e empty -s exit:0 \
256	    sh -c "pid=${ATF_TMPDIR}/nc.pid; daemon -p \$pid nc -lU j; sleep 2; pkill -F \$pid"
257
258	atf_check -e empty -o match:'a/' -s exit:0 ls -F
259	atf_check -e empty -o match:'c@' -s exit:0 ls -F
260	atf_check -e empty -o match:'h\|' -s exit:0 ls -F
261	atf_check -e empty -o match:'j=' -s exit:0 ls -F
262	#atf_check -e empty -o match:'<whiteout-file>%' -s exit:0 ls -F
263	atf_check -e empty -o match:'stuv' -s exit:0 ls -F
264	atf_check -e empty -o match:'wxyz\*' -s exit:0 ls -F
265}
266
267atf_test_case H_flag
268H_flag_head()
269{
270	atf_set "descr" "Verify that ls -H follows symlinks"
271}
272
273H_flag_body()
274{
275	create_test_inputs
276
277	atf_check -e empty -o match:'1' -s exit:0 ls -H c
278}
279
280atf_test_case I_flag
281I_flag_head()
282{
283	atf_set "descr" "Verify that the output from ls -I is the same as ls for an unprivileged user"
284}
285
286I_flag_body()
287{
288	create_test_inputs
289
290	WITH_I=$PWD/../with_I.out
291	WITHOUT_I=$PWD/../without_I.out
292
293	atf_check -e empty -o save:$WITH_I -s exit:0 ls -I
294	atf_check -e empty -o save:$WITHOUT_I -s exit:0 ls
295
296	echo "Explicit -I usage"
297	cat $WITH_I
298	echo "No -I usage"
299	cat $WITHOUT_I
300
301	atf_check_equal "$(cat $WITH_I)" "$(cat $WITHOUT_I)"
302}
303
304atf_test_case I_flag_voids_implied_A_flag_when_root
305I_flag_voids_implied_A_flag_when_root_head()
306{
307	atf_set "descr" "Verify that -I voids out implied -A for root"
308	atf_set "require.user" "root"
309}
310
311I_flag_voids_implied_A_flag_when_root_body()
312{
313	create_test_inputs
314
315	atf_check -o not-match:'\.f' -s exit:0 ls -I
316	atf_check -o not-match:'\.g' -s exit:0 ls -I
317
318	atf_check -o match:'\.f' -s exit:0 ls -A -I
319	atf_check -o match:'\.g' -s exit:0 ls -A -I
320}
321
322atf_test_case L_flag
323L_flag_head()
324{
325	atf_set "descr" "Verify that -L prints out the symbolic link and conversely -P prints out the target for the symbolic link"
326}
327
328L_flag_body()
329{
330	atf_check -e empty -o empty -s exit:0 ln -s target1/target2 link1
331	atf_check -e empty -o match:link1 -s exit:0 ls -L
332	atf_check -e empty -o not-match:target1/target2 -s exit:0 ls -L
333}
334
335atf_test_case R_flag
336R_flag_head()
337{
338	atf_set "descr" "Verify that the output from ls -R prints out the directory contents recursively"
339}
340
341R_flag_body()
342{
343	create_test_inputs
344
345	WITH_R=$PWD/../with_R.out
346	WITH_R_expected_output=$PWD/../with_R_expected.out
347
348	atf_check -e empty -o save:$WITH_R -s exit:0 ls -R
349
350	set -- . $(find -s . \! -name '.*' -type d)
351	while [ $# -gt 0 ]; do
352		dir=$1; shift
353		[ "$dir" != "." ] && echo "$dir:"
354		(cd $dir && ls -1A | sed -e '/^\./d')
355		[ $# -ne 0 ] && echo
356	done > $WITH_R_expected_output
357
358	echo "-R usage"
359	cat $WITH_R
360	echo "-R expected output"
361	cat $WITH_R_expected_output
362
363	atf_check_equal "$(cat $WITH_R)" "$(cat $WITH_R_expected_output)"
364}
365
366atf_test_case S_flag
367S_flag_head()
368{
369	atf_set "descr" "Verify that -S sorts by file size, then by filename lexicographically"
370}
371
372S_flag_body()
373{
374	create_test_dir
375
376	file_list_dir=$PWD/../files
377
378	atf_check -e empty -o empty -s exit:0 mkdir -p $file_list_dir
379
380	create_test_inputs
381	create_test_inputs2
382
383	WITH_S=$PWD/../with_S.out
384	WITHOUT_S=$PWD/../without_S.out
385
386	atf_check -e empty -o save:$WITH_S ls -D '%s' -lS
387	atf_check -e empty -o save:$WITHOUT_S ls -D '%s' -l
388
389	WITH_S_parsed=$(awk '! /^total/ { print $7 }' $WITH_S)
390	set -- $(awk '! /^total/ { print $5, $7 }' $WITHOUT_S)
391	while [ $# -gt 0 ]; do
392		size=$1; shift
393		filename=$1; shift
394		echo $filename >> $file_list_dir/${size}
395	done
396	file_lists=$(find $file_list_dir -type f -exec basename {} \; | sort -nr)
397	WITHOUT_S_parsed=$(for file_list in $file_lists; do sort < $file_list_dir/$file_list; done)
398
399	echo "-lS usage (parsed)"
400	echo "$WITH_S_parsed"
401	echo "-l usage (parsed)"
402	echo "$WITHOUT_S_parsed"
403
404	atf_check_equal "$WITHOUT_S_parsed" "$WITH_S_parsed"
405}
406
407atf_test_case T_flag
408T_flag_head()
409{
410	atf_set "descr" "Verify -T support"
411}
412
413T_flag_body()
414{
415	create_test_dir
416
417	atf_check -e empty -o empty -s exit:0 touch a.file
418
419	mtime_in_secs=$(stat -f %m -t %s a.file)
420	mtime=$(date -j -f %s $mtime_in_secs +"[[:space:]]+%b[[:space:]]+%e[[:space:]]+%H:%M:%S[[:space:]]+%Y")
421
422	atf_check -e empty -o match:"$mtime"'[[:space:]]+a\.file' \
423	    -s exit:0 ls -lT a.file
424}
425
426atf_test_case a_flag
427a_flag_head()
428{
429	atf_set "descr" "Verify -a support"
430}
431
432a_flag_body()
433{
434	create_test_dir
435
436	# Make sure "." and ".." show up with -a
437	atf_check -e empty -o match:'\.[[:space:]]+\.\.'  -s exit:0 ls -ax
438
439	create_test_inputs
440
441	WITH_a=$PWD/../with_a.out
442	WITHOUT_a=$PWD/../without_a.out
443
444	atf_check -e empty -o save:$WITH_a -s exit:0 ls -a
445	atf_check -e empty -o save:$WITHOUT_a -s exit:0 ls
446
447	echo "-a usage"
448	cat $WITH_a
449	echo "No -a usage"
450	cat $WITHOUT_a
451
452	for dot_path in '\.f' '\.g'; do
453		atf_check -e empty -o not-empty -s exit:0 grep "${dot_path}" \
454		    $WITH_a
455		atf_check -e empty -o empty -s not-exit:0 grep "${dot_path}" \
456		    $WITHOUT_a
457	done
458}
459
460atf_test_case b_flag
461b_flag_head()
462{
463	atf_set "descr" "Verify that the output from ls -b prints out non-printable characters"
464}
465
466b_flag_body()
467{
468	atf_check -e empty -o empty -s exit:0 touch "$(printf "y\013z")"
469	atf_check -e empty -o match:'y\\vz' -s exit:0 ls -b
470}
471
472atf_test_case d_flag
473d_flag_head()
474{
475	atf_set "descr" "Verify that -d doesn't descend down directories"
476}
477
478d_flag_body()
479{
480	create_test_dir
481
482	output=$PWD/../output
483
484	atf_check -e empty -o empty -s exit:0 mkdir -p a/b
485
486	for path in . $PWD a; do
487		atf_check -e empty -o save:$output -s exit:0 ls -d $path
488		atf_check_equal "$(cat $output)" "$path"
489	done
490}
491
492atf_test_case f_flag
493f_flag_head()
494{
495	atf_set "descr" "Verify that -f prints out the contents of a directory unsorted"
496}
497
498f_flag_body()
499{
500	create_test_inputs
501
502	output=$PWD/../output
503
504	# XXX: I don't have enough understanding of how the algorithm works yet
505	# to determine more than the fact that all the entries printed out
506	# exist
507	paths=$(find -s . -mindepth 1 -maxdepth 1 \! -name '.*' -exec basename {} \; )
508
509	atf_check -e empty -o save:$output -s exit:0 ls -f
510
511	for path in $paths; do
512		atf_check -e ignore -o not-empty -s exit:0 \
513		    egrep "^$path$" $output
514	done
515}
516
517atf_test_case g_flag
518g_flag_head()
519{
520	atf_set "descr" "Verify that -g does nothing (compatibility flag)"
521}
522
523g_flag_body()
524{
525	create_test_inputs2
526	for file in $files; do
527		atf_check -e empty -o match:"$(ls -a $file)" -s exit:0 \
528		    ls -ag $file
529		atf_check -e empty -o match:"$(ls -la $file)" -s exit:0 \
530		    ls -alg $file
531	done
532}
533
534atf_test_case h_flag
535h_flag_head()
536{
537	atf_set "descr" "Verify that -h prints out the humanized units for file sizes with ls -l"
538	atf_set "require.files" "/usr/bin/bc"
539}
540
541h_flag_body()
542{
543	# XXX: this test doesn't currently show how 999 bytes will be 999B,
544	# but 1000 bytes will be 1.0K, due to how humanize_number(3) works.
545	create_test_inputs2
546	for file in $files; do
547		file_size=$(stat -f '%z' "$file") || \
548		    atf_fail "stat'ing $file failed"
549		scale=2
550		if [ $file_size -lt $KB ]; then
551			divisor=1
552			scale=0
553			suffix=B
554		elif [ $file_size -lt $MB ]; then
555			divisor=$KB
556			suffix=K
557		elif [ $file_size -lt $GB ]; then
558			divisor=$MB
559			suffix=M
560		elif [ $file_size -lt $TB ]; then
561			divisor=$GB
562			suffix=G
563		elif [ $file_size -lt $PB ]; then
564			divisor=$TB
565			suffix=T
566		else
567			divisor=$PB
568			suffix=P
569		fi
570
571		bc_expr="$(printf "scale=%s\n%s/%s\nquit" $scale $file_size $divisor)"
572		size_humanized=$(bc -e "$bc_expr" | tr '.' '\.' | sed -e 's,\.00,,')
573
574		atf_check -e empty -o match:"$size_humanized.+$file" \
575		    -s exit:0 ls -hl $file
576	done
577}
578
579atf_test_case i_flag
580i_flag_head()
581{
582	atf_set "descr" "Verify that -i prints out the inode for files"
583}
584
585i_flag_body()
586{
587	create_test_inputs
588
589	paths=$(find -L . -mindepth 1)
590	[ -n "$paths" ] || atf_skip 'Could not find any paths to iterate over (!)'
591
592	for path in $paths; do
593		atf_check -e empty \
594		    -o match:"$(stat -f '[[:space:]]*%i[[:space:]]+%N' $path)" \
595		    -s exit:0 ls -d1i $path
596	done
597}
598
599atf_test_case k_flag
600k_flag_head()
601{
602	atf_set "descr" "Verify that -k prints out the size with a block size of 1kB"
603}
604
605k_flag_body()
606{
607	create_test_inputs2
608	for file in $files; do
609		atf_check -e empty \
610		    -o match:"[[:space:]]+$(stat -f "%z" $file)[[:space:]]+.+[[:space:]]+$file" ls -lk $file
611	done
612}
613
614atf_test_case l_flag
615l_flag_head()
616{
617	atf_set "descr" "Verify that -l prints out the output in long format"
618}
619
620l_flag_body()
621{
622
623	atf_check -e empty -o empty -s exit:0 touch a.file
624
625	mtime_in_secs=$(stat -f "%m" -t "%s" a.file)
626	mtime=$(date -j -f "%s" $mtime_in_secs +"%b[[:space:]]+%e[[:space:]]+%H:%M")
627
628	expected_output=$(stat -f "%Sp[[:space:]]+%l[[:space:]]+%Su[[:space:]]+%Sg[[:space:]]+%z[[:space:]]+$mtime[[:space:]]+a\\.file" a.file)
629
630	atf_check -e empty -o match:"$expected_output" -s exit:0 ls -l a.file
631}
632
633atf_test_case lcomma_flag
634lcomma_flag_head()
635{
636	atf_set "descr" "Verify that -l, prints out the size with ',' delimiters"
637}
638
639lcomma_flag_body()
640{
641	create_test_inputs
642
643	atf_check \
644	    -o match:'\-rw\-r\-\-r\-\-[[:space:]]+.+[[:space:]]+1,000[[:space:]]+.+i' \
645	    env LC_ALL=en_US.ISO8859-1 ls -l, i
646}
647
648atf_test_case m_flag
649m_flag_head()
650{
651	atf_set "descr" "Verify that the output from ls -m is comma-separated"
652}
653
654m_flag_body()
655{
656	create_test_dir
657
658	output=$PWD/../output
659
660	atf_check -e empty -o empty -s exit:0 touch ,, "a,b " c d e
661
662	atf_check -e empty -o save:$output -s exit:0 ls -m
663
664	atf_check_equal "$(cat $output)" ",,, a,b , c, d, e"
665}
666
667atf_test_case n_flag
668n_flag_head()
669{
670	atf_set "descr" "Verify that the output from ls -n prints out numeric GIDs/UIDs instead of symbolic GIDs/UIDs"
671	atf_set "require.user" "root"
672}
673
674n_flag_body()
675{
676	daemon_gid=$(id -g daemon) || atf_skip "could not resolve gid for daemon (!)"
677	nobody_uid=$(id -u nobody) || atf_skip "could not resolve uid for nobody (!)"
678
679	atf_check -e empty -o empty -s exit:0 touch a.file
680	atf_check -e empty -o empty -s exit:0 chown $nobody_uid:$daemon_gid a.file
681
682	atf_check -e empty \
683	    -o match:'\-rw\-r\-\-r\-\-[[:space:]]+1[[:space:]]+'"$nobody_uid[[:space:]]+$daemon_gid"'[[:space:]]+.+a\.file' \
684	    ls -ln a.file
685
686}
687
688atf_test_case o_flag
689o_flag_head()
690{
691	atf_set "descr" "Verify that the output from ls -o prints out the chflag values or '-' if none are set"
692	atf_set "require.user" "root"
693}
694
695o_flag_body()
696{
697	local size=12345
698
699	create_test_dir
700
701	atf_check -e ignore -o empty -s exit:0 dd if=/dev/zero of=a.file \
702	    bs=$size count=1
703	atf_check -e ignore -o empty -s exit:0 dd if=/dev/zero of=b.file \
704	    bs=$size count=1
705	atf_check -e empty -o empty -s exit:0 chflags uarch a.file
706
707	atf_check -e empty -o match:"[[:space:]]+uarch[[:space:]]$size+.+a\\.file" \
708	    -s exit:0 ls -lo a.file
709	atf_check -e empty -o match:"[[:space:]]+\\-[[:space:]]$size+.+b\\.file" \
710	    -s exit:0 ls -lo b.file
711}
712
713atf_test_case p_flag
714p_flag_head()
715{
716	atf_set "descr" "Verify that the output from ls -p prints out '/' after directories"
717}
718
719p_flag_body()
720{
721	create_test_inputs
722
723	paths=$(find -L .)
724	[ -n "$paths" ] || atf_skip 'Could not find any paths to iterate over (!)'
725
726	for path in $paths; do
727		suffix=
728		# If path is not a symlink and is a directory, then the suffix
729		# must be "/".
730		if [ ! -L "${path}" -a -d "$path" ]; then
731			suffix=/
732		fi
733		atf_check -e empty -o match:"$path${suffix}" -s exit:0 \
734		    ls -dp $path
735	done
736}
737
738atf_test_case q_flag_and_w_flag
739q_flag_and_w_flag_head()
740{
741	atf_set "descr" "Verify that the output from ls -q prints out '?' for ESC and ls -w prints out the escape character"
742}
743
744q_flag_and_w_flag_body()
745{
746	create_test_dir
747
748	test_file="$(printf "y\01z")"
749
750	atf_check -e empty -o empty -s exit:0 touch "$test_file"
751
752	atf_check -e empty -o match:'y\?z' -s exit:0 ls -q "$test_file"
753	atf_check -e empty -o match:"$test_file" -s exit:0 ls -w "$test_file"
754}
755
756atf_test_case r_flag
757r_flag_head()
758{
759	atf_set "descr" "Verify that the output from ls -r sorts the same way as reverse sorting with sort(1)"
760}
761
762r_flag_body()
763{
764	create_test_inputs
765
766	WITH_r=$PWD/../with_r.out
767	WITH_sort=$PWD/../with_sort.out
768
769	atf_check -e empty -o save:$WITH_r -s exit:0 ls -1r
770	atf_check -e empty -o save:$WITH_sort -s exit:0 sh -c 'ls -1 | sort -r'
771
772	echo "Sorted with -r"
773	cat $WITH_r
774	echo "Reverse sorted with sort(1)"
775	cat $WITH_sort
776
777	atf_check_equal "$(cat $WITH_r)" "$(cat $WITH_sort)"
778}
779
780atf_test_case s_flag
781s_flag_head()
782{
783	atf_set "descr" "Verify that the output from ls -s matches the output from stat(1)"
784}
785
786s_flag_body()
787{
788	create_test_inputs2
789	for file in $files; do
790		atf_check -e empty \
791		    -o match:"$(stat -f "%b" $file)[[:space:]]+$file" ls -s $file
792	done
793}
794
795atf_test_case t_flag
796t_flag_head()
797{
798	atf_set "descr" "Verify that the output from ls -t sorts by modification time"
799}
800
801t_flag_body()
802{
803	create_test_dir
804
805	atf_check -e empty -o empty -s exit:0 touch a.file
806	atf_check -e empty -o empty -s exit:0 touch b.file
807
808	atf_check -e empty -o match:'a\.file' -s exit:0 sh -c 'ls -lt | tail -n 1'
809	atf_check -e empty -o match:'b\.file.*a\.file' -s exit:0 ls -Ct
810
811	atf_check -e empty -o empty -s exit:0 rm a.file
812	atf_check -e empty -o empty -s exit:0 sh -c 'echo "i am a" > a.file'
813
814	atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lt | tail -n 1'
815	atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Ct
816}
817
818atf_test_case u_flag
819u_flag_head()
820{
821	atf_set "descr" "Verify that the output from ls -u sorts by last access"
822}
823
824u_flag_body()
825{
826	create_test_dir
827
828	atf_check -e empty -o empty -s exit:0 touch a.file
829	atf_check -e empty -o empty -s exit:0 touch b.file
830
831	atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lu | tail -n 1'
832	atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Cu
833
834	atf_check -e empty -o empty -s exit:0 sh -c 'echo "i am a" > a.file'
835	atf_check -e empty -o match:'i am a' -s exit:0 cat a.file
836
837	atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lu | tail -n 1'
838	atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Cu
839}
840
841atf_test_case x_flag
842x_flag_head()
843{
844	atf_set "descr" "Verify that the output from ls -x is multi-column, sorted across"
845}
846
847x_flag_body()
848{
849	create_test_inputs
850
851	WITH_x=$PWD/../with_x.out
852
853	atf_check -e empty -o save:$WITH_x -s exit:0 ls -x
854
855	echo "With -x usage"
856	cat $WITH_x
857
858	atf_check -e ignore -o not-empty -s exit:0 \
859	    egrep "a[[:space:]]+c[[:space:]]+d[[:space:]]+e[[:space:]]+h" $WITH_x
860	atf_check -e ignore -o not-empty -s exit:0 \
861	    egrep "i[[:space:]]+klmn[[:space:]]+opqr[[:space:]]+stuv[[:space:]]+wxyz" $WITH_x
862}
863
864atf_test_case y_flag
865y_flag_head()
866{
867	atf_set "descr" "Verify that the output from ls -y sorts the same way as sort(1)"
868}
869
870y_flag_body()
871{
872	create_test_inputs
873
874	WITH_sort=$PWD/../with_sort.out
875	WITH_y=$PWD/../with_y.out
876
877	atf_check -e empty -o save:$WITH_sort -s exit:0 sh -c 'ls -1 | sort'
878	atf_check -e empty -o save:$WITH_y -s exit:0 ls -1y
879
880	echo "Sorted with sort(1)"
881	cat $WITH_sort
882	echo "Sorted with -y"
883	cat $WITH_y
884
885	atf_check_equal "$(cat $WITH_sort)" "$(cat $WITH_y)"
886}
887
888atf_test_case 1_flag
8891_flag_head()
890{
891	atf_set "descr" "Verify that -1 prints out one item per line"
892}
893
8941_flag_body()
895{
896	create_test_inputs
897
898	WITH_1=$PWD/../with_1.out
899	WITHOUT_1=$PWD/../without_1.out
900
901	atf_check -e empty -o save:$WITH_1 -s exit:0 ls -1
902	atf_check -e empty -o save:$WITHOUT_1 -s exit:0 \
903		sh -c 'for i in $(ls); do echo $i; done'
904
905	echo "Explicit -1 usage"
906	cat $WITH_1
907	echo "No -1 usage"
908	cat $WITHOUT_1
909
910	atf_check_equal "$(cat $WITH_1)" "$(cat $WITHOUT_1)"
911}
912
913atf_init_test_cases()
914{
915	export BLOCKSIZE=512
916
917	atf_add_test_case A_flag
918	atf_add_test_case A_flag_implied_when_root
919	atf_add_test_case B_flag
920	atf_add_test_case C_flag
921	atf_add_test_case D_flag
922	atf_add_test_case F_flag
923	#atf_add_test_case G_flag
924	atf_add_test_case H_flag
925	atf_add_test_case I_flag
926	atf_add_test_case I_flag_voids_implied_A_flag_when_root
927	atf_add_test_case L_flag
928	#atf_add_test_case P_flag
929	atf_add_test_case R_flag
930	atf_add_test_case S_flag
931	atf_add_test_case T_flag
932	#atf_add_test_case U_flag
933	#atf_add_test_case W_flag
934	#atf_add_test_case Z_flag
935	atf_add_test_case a_flag
936	atf_add_test_case b_flag
937	#atf_add_test_case c_flag
938	atf_add_test_case d_flag
939	atf_add_test_case f_flag
940	atf_add_test_case g_flag
941	atf_add_test_case h_flag
942	atf_add_test_case i_flag
943	atf_add_test_case k_flag
944	atf_add_test_case l_flag
945	atf_add_test_case lcomma_flag
946	atf_add_test_case m_flag
947	atf_add_test_case n_flag
948	atf_add_test_case o_flag
949	atf_add_test_case p_flag
950	atf_add_test_case q_flag_and_w_flag
951	atf_add_test_case r_flag
952	atf_add_test_case s_flag
953	atf_add_test_case t_flag
954	atf_add_test_case u_flag
955	atf_add_test_case x_flag
956	atf_add_test_case y_flag
957	atf_add_test_case 1_flag
958}
959