ls_tests.sh revision 289965
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: stable/10/bin/ls/tests/ls_tests.sh 289965 2015-10-25 23:03:04Z ngie $
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_skip "kyua report-jenkins doesn't properly escape non-printable chars: https://github.com/jmmv/kyua/issues/136"
174
175	atf_check -e empty -o empty -s exit:0 touch "$(printf "y\013z")"
176	atf_check -e empty -o match:'y\\013z' -s exit:0 ls -B
177}
178
179atf_test_case C_flag
180C_flag_head()
181{
182	atf_set "descr" "Verify that the output from ls -C is multi-column, sorted down"
183}
184
185print_index()
186{
187	local i=1
188	local wanted_index=$1; shift
189
190	while [ $i -le $wanted_index ]; do
191		if [ $i -eq $wanted_index ]; then
192			echo $1
193			return
194		fi
195		shift
196		: $(( i += 1 ))
197	done
198}
199
200C_flag_body()
201{
202	create_test_inputs
203
204	WITH_C=$PWD/../with_C.out
205
206	export COLUMNS=40
207	atf_check -e empty -o save:$WITH_C -s exit:0 ls -C
208
209	echo "With -C usage"
210	cat $WITH_C
211
212	paths=$(find -s . -mindepth 1 -maxdepth 1 \! -name '.*' -exec basename {} \; )
213	set -- $paths
214	num_paths=$#
215	num_columns=2
216
217	max_num_paths_per_column=$(( $(( $num_paths + 1 )) / $num_columns ))
218
219	local i=1
220	while [ $i -le $max_num_paths_per_column ]; do
221		column_1=$(print_index $i $paths)
222		column_2=$(print_index $(( $i + $max_num_paths_per_column )) $paths)
223		#echo "paths[$(( $i + $max_num_paths_per_column ))] = $column_2"
224		expected_expr="$column_1"
225		if [ -n "$column_2" ]; then
226			expected_expr="$expected_expr[[:space:]]+$column_2"
227		fi
228		atf_check -e ignore -o not-empty -s exit:0 \
229		    egrep "$expected_expr" $WITH_C
230		: $(( i += 1 ))
231	done
232}
233
234atf_test_case D_flag
235D_flag_head()
236{
237	atf_set "descr" "Verify that the output from ls -D modifies the time format used with ls -l"
238}
239
240D_flag_body()
241{
242	atf_check -e empty -o empty -s exit:0 touch a.file
243	atf_check -e empty -o match:"$(stat -f '%c[[:space:]]+%N' a.file)" \
244	    -s exit:0 ls -lD '%s'
245}
246
247atf_test_case F_flag
248F_flag_head()
249{
250	atf_set "descr" "Verify that the output from ls -F prints out appropriate symbols after files"
251}
252
253F_flag_body()
254{
255	create_test_inputs
256
257	atf_check -e empty -s exit:0 \
258	    sh -c "pid=${ATF_TMPDIR}/nc.pid; daemon -p \$pid nc -lU j; sleep 2; pkill -F \$pid"
259
260	atf_check -e empty -o match:'a/' -s exit:0 ls -F
261	atf_check -e empty -o match:'c@' -s exit:0 ls -F
262	atf_check -e empty -o match:'h\|' -s exit:0 ls -F
263	atf_check -e empty -o match:'j=' -s exit:0 ls -F
264	#atf_check -e empty -o match:'<whiteout-file>%' -s exit:0 ls -F
265	atf_check -e empty -o match:'stuv' -s exit:0 ls -F
266	atf_check -e empty -o match:'wxyz\*' -s exit:0 ls -F
267}
268
269atf_test_case H_flag
270H_flag_head()
271{
272	atf_set "descr" "Verify that ls -H follows symlinks"
273}
274
275H_flag_body()
276{
277	create_test_inputs
278
279	atf_check -e empty -o match:'1' -s exit:0 ls -H c
280}
281
282atf_test_case I_flag
283I_flag_head()
284{
285	atf_set "descr" "Verify that the output from ls -I is the same as ls for an unprivileged user"
286}
287
288I_flag_body()
289{
290	create_test_inputs
291
292	WITH_I=$PWD/../with_I.out
293	WITHOUT_I=$PWD/../without_I.out
294
295	atf_check -e empty -o save:$WITH_I -s exit:0 ls -I
296	atf_check -e empty -o save:$WITHOUT_I -s exit:0 ls
297
298	echo "Explicit -I usage"
299	cat $WITH_I
300	echo "No -I usage"
301	cat $WITHOUT_I
302
303	atf_check_equal "$(cat $WITH_I)" "$(cat $WITHOUT_I)"
304}
305
306atf_test_case I_flag_voids_implied_A_flag_when_root
307I_flag_voids_implied_A_flag_when_root_head()
308{
309	atf_set "descr" "Verify that -I voids out implied -A for root"
310	atf_set "require.user" "root"
311}
312
313I_flag_voids_implied_A_flag_when_root_body()
314{
315	create_test_inputs
316
317	atf_check -o not-match:'\.f' -s exit:0 ls -I
318	atf_check -o not-match:'\.g' -s exit:0 ls -I
319
320	atf_check -o match:'\.f' -s exit:0 ls -A -I
321	atf_check -o match:'\.g' -s exit:0 ls -A -I
322}
323
324atf_test_case L_flag
325L_flag_head()
326{
327	atf_set "descr" "Verify that -L prints out the symbolic link and conversely -P prints out the target for the symbolic link"
328}
329
330L_flag_body()
331{
332	atf_check -e empty -o empty -s exit:0 ln -s target1/target2 link1
333	atf_check -e empty -o match:link1 -s exit:0 ls -L
334	atf_check -e empty -o not-match:target1/target2 -s exit:0 ls -L
335}
336
337atf_test_case R_flag
338R_flag_head()
339{
340	atf_set "descr" "Verify that the output from ls -R prints out the directory contents recursively"
341}
342
343R_flag_body()
344{
345	create_test_inputs
346
347	WITH_R=$PWD/../with_R.out
348	WITH_R_expected_output=$PWD/../with_R_expected.out
349
350	atf_check -e empty -o save:$WITH_R -s exit:0 ls -R
351
352	set -- . $(find -s . \! -name '.*' -type d)
353	while [ $# -gt 0 ]; do
354		dir=$1; shift
355		[ "$dir" != "." ] && echo "$dir:"
356		(cd $dir && ls -1A | sed -e '/^\./d')
357		[ $# -ne 0 ] && echo
358	done > $WITH_R_expected_output
359
360	echo "-R usage"
361	cat $WITH_R
362	echo "-R expected output"
363	cat $WITH_R_expected_output
364
365	atf_check_equal "$(cat $WITH_R)" "$(cat $WITH_R_expected_output)"
366}
367
368atf_test_case S_flag
369S_flag_head()
370{
371	atf_set "descr" "Verify that -S sorts by file size, then by filename lexicographically"
372}
373
374S_flag_body()
375{
376	create_test_dir
377
378	file_list_dir=$PWD/../files
379
380	atf_check -e empty -o empty -s exit:0 mkdir -p $file_list_dir
381
382	create_test_inputs
383	create_test_inputs2
384
385	WITH_S=$PWD/../with_S.out
386	WITHOUT_S=$PWD/../without_S.out
387
388	atf_check -e empty -o save:$WITH_S ls -D '%s' -lS
389	atf_check -e empty -o save:$WITHOUT_S ls -D '%s' -l
390
391	WITH_S_parsed=$(awk '! /^total/ { print $7 }' $WITH_S)
392	set -- $(awk '! /^total/ { print $5, $7 }' $WITHOUT_S)
393	while [ $# -gt 0 ]; do
394		size=$1; shift
395		filename=$1; shift
396		echo $filename >> $file_list_dir/${size}
397	done
398	file_lists=$(find $file_list_dir -type f -exec basename {} \; | sort -nr)
399	WITHOUT_S_parsed=$(for file_list in $file_lists; do sort < $file_list_dir/$file_list; done)
400
401	echo "-lS usage (parsed)"
402	echo "$WITH_S_parsed"
403	echo "-l usage (parsed)"
404	echo "$WITHOUT_S_parsed"
405
406	atf_check_equal "$WITHOUT_S_parsed" "$WITH_S_parsed"
407}
408
409atf_test_case T_flag
410T_flag_head()
411{
412	atf_set "descr" "Verify -T support"
413}
414
415T_flag_body()
416{
417	create_test_dir
418
419	atf_check -e empty -o empty -s exit:0 touch a.file
420
421	birthtime_in_secs=$(stat -f %B -t %s a.file)
422	birthtime=$(date -j -f %s $birthtime_in_secs +"[[:space:]]+%b[[:space:]]+%e[[:space:]]+%H:%M:%S[[:space:]]+%Y")
423
424	atf_check -e empty -o match:"$birthtime"'[[:space:]]+a\.file' \
425	    -s exit:0 ls -lT a.file
426}
427
428atf_test_case a_flag
429a_flag_head()
430{
431	atf_set "descr" "Verify -a support"
432}
433
434a_flag_body()
435{
436	create_test_dir
437
438	# Make sure "." and ".." show up with -a
439	atf_check -e empty -o match:'\.[[:space:]]+\.\.'  -s exit:0 ls -ax
440
441	create_test_inputs
442
443	WITH_a=$PWD/../with_a.out
444	WITHOUT_a=$PWD/../without_a.out
445
446	atf_check -e empty -o save:$WITH_a -s exit:0 ls -a
447	atf_check -e empty -o save:$WITHOUT_a -s exit:0 ls
448
449	echo "-a usage"
450	cat $WITH_a
451	echo "No -a usage"
452	cat $WITHOUT_a
453
454	for dot_path in '\.f' '\.g'; do
455		atf_check -e empty -o not-empty -s exit:0 grep "${dot_path}" \
456		    $WITH_a
457		atf_check -e empty -o empty -s not-exit:0 grep "${dot_path}" \
458		    $WITHOUT_a
459	done
460}
461
462atf_test_case b_flag
463b_flag_head()
464{
465	atf_set "descr" "Verify that the output from ls -b prints out non-printable characters"
466}
467
468b_flag_body()
469{
470	atf_skip "kyua report-jenkins doesn't properly escape non-printable chars: https://github.com/jmmv/kyua/issues/136"
471
472	atf_check -e empty -o empty -s exit:0 touch "$(printf "y\013z")"
473	atf_check -e empty -o match:'y\\vz' -s exit:0 ls -b
474}
475
476atf_test_case d_flag
477d_flag_head()
478{
479	atf_set "descr" "Verify that -d doesn't descend down directories"
480}
481
482d_flag_body()
483{
484	create_test_dir
485
486	output=$PWD/../output
487
488	atf_check -e empty -o empty -s exit:0 mkdir -p a/b
489
490	for path in . $PWD a; do
491		atf_check -e empty -o save:$output -s exit:0 ls -d $path
492		atf_check_equal "$(cat $output)" "$path"
493	done
494}
495
496atf_test_case f_flag
497f_flag_head()
498{
499	atf_set "descr" "Verify that -f prints out the contents of a directory unsorted"
500}
501
502f_flag_body()
503{
504	create_test_inputs
505
506	output=$PWD/../output
507
508	# XXX: I don't have enough understanding of how the algorithm works yet
509	# to determine more than the fact that all the entries printed out
510	# exist
511	paths=$(find -s . -mindepth 1 -maxdepth 1 \! -name '.*' -exec basename {} \; )
512
513	atf_check -e empty -o save:$output -s exit:0 ls -f
514
515	for path in $paths; do
516		atf_check -e ignore -o not-empty -s exit:0 \
517		    egrep "^$path$" $output
518	done
519}
520
521atf_test_case g_flag
522g_flag_head()
523{
524	atf_set "descr" "Verify that -g does nothing (compatibility flag)"
525}
526
527g_flag_body()
528{
529	create_test_inputs2
530	for file in $files; do
531		atf_check -e empty -o match:"$(ls -a $file)" -s exit:0 \
532		    ls -ag $file
533		atf_check -e empty -o match:"$(ls -la $file)" -s exit:0 \
534		    ls -alg $file
535	done
536}
537
538atf_test_case h_flag
539h_flag_head()
540{
541	atf_set "descr" "Verify that -h prints out the humanized units for file sizes with ls -l"
542	atf_set "require.files" "/usr/bin/bc"
543}
544
545h_flag_body()
546{
547	# XXX: this test doesn't currently show how 999 bytes will be 999B,
548	# but 1000 bytes will be 1.0K, due to how humanize_number(3) works.
549	create_test_inputs2
550	for file in $files; do
551		file_size=$(stat -f '%z' "$file") || \
552		    atf_fail "stat'ing $file failed"
553		scale=2
554		if [ $file_size -lt $KB ]; then
555			divisor=1
556			scale=0
557			suffix=B
558		elif [ $file_size -lt $MB ]; then
559			divisor=$KB
560			suffix=K
561		elif [ $file_size -lt $GB ]; then
562			divisor=$MB
563			suffix=M
564		elif [ $file_size -lt $TB ]; then
565			divisor=$GB
566			suffix=G
567		elif [ $file_size -lt $PB ]; then
568			divisor=$TB
569			suffix=T
570		else
571			divisor=$PB
572			suffix=P
573		fi
574
575		bc_expr="$(printf "scale=%s\n%s/%s\nquit" $scale $file_size $divisor)"
576		size_humanized=$(bc -e "$bc_expr" | tr '.' '\.' | sed -e 's,\.00,,')
577
578		atf_check -e empty -o match:"$size_humanized.+$file" \
579		    -s exit:0 ls -hl $file
580	done
581}
582
583atf_test_case i_flag
584i_flag_head()
585{
586	atf_set "descr" "Verify that -i prints out the inode for files"
587}
588
589i_flag_body()
590{
591	create_test_inputs
592
593	paths=$(find -L . -mindepth 1)
594	[ -n "$paths" ] || atf_skip 'Could not find any paths to iterate over (!)'
595
596	for path in $paths; do
597		atf_check -e empty \
598		    -o match:"$(stat -f '[[:space:]]*%i[[:space:]]+%N' $path)" \
599		    -s exit:0 ls -d1i $path
600	done
601}
602
603atf_test_case k_flag
604k_flag_head()
605{
606	atf_set "descr" "Verify that -k prints out the size with a block size of 1kB"
607}
608
609k_flag_body()
610{
611	create_test_inputs2
612	for file in $files; do
613		atf_check -e empty \
614		    -o match:"[[:space:]]+$(stat -f "%z" $file)[[:space:]]+.+[[:space:]]+$file" ls -lk $file
615	done
616}
617
618atf_test_case l_flag
619l_flag_head()
620{
621	atf_set "descr" "Verify that -l prints out the output in long format"
622}
623
624l_flag_body()
625{
626
627	atf_check -e empty -o empty -s exit:0 touch a.file
628
629	birthtime_in_secs=$(stat -f "%B" -t "%s" a.file)
630	birthtime=$(date -j -f "%s" $birthtime_in_secs +"%b[[:space:]]+%e[[:space:]]+%H:%M")
631
632	expected_output=$(stat -f "%Sp[[:space:]]+%l[[:space:]]+%Su[[:space:]]+%Sg[[:space:]]+%z[[:space:]]+$birthtime[[:space:]]+a\\.file" a.file)
633
634	atf_check -e empty -o match:"$expected_output" -s exit:0 ls -l a.file
635}
636
637atf_test_case lcomma_flag
638lcomma_flag_head()
639{
640	atf_set "descr" "Verify that -l, prints out the size with ',' delimiters"
641}
642
643lcomma_flag_body()
644{
645	create_test_inputs
646
647	atf_check \
648	    -o match:'\-rw\-r\-\-r\-\-[[:space:]]+.+[[:space:]]+1,000[[:space:]]+.+i' \
649	    env LC_ALL=en_US.ISO8859-1 ls -l, i
650}
651
652atf_test_case m_flag
653m_flag_head()
654{
655	atf_set "descr" "Verify that the output from ls -m is comma-separated"
656}
657
658m_flag_body()
659{
660	create_test_dir
661
662	output=$PWD/../output
663
664	atf_check -e empty -o empty -s exit:0 touch ,, "a,b " c d e
665
666	atf_check -e empty -o save:$output -s exit:0 ls -m
667
668	atf_check_equal "$(cat $output)" ",,, a,b , c, d, e"
669}
670
671atf_test_case n_flag
672n_flag_head()
673{
674	atf_set "descr" "Verify that the output from ls -n prints out numeric GIDs/UIDs instead of symbolic GIDs/UIDs"
675	atf_set "require.user" "root"
676}
677
678n_flag_body()
679{
680	daemon_gid=$(id -g daemon) || atf_skip "could not resolve gid for daemon (!)"
681	nobody_uid=$(id -u nobody) || atf_skip "could not resolve uid for nobody (!)"
682
683	atf_check -e empty -o empty -s exit:0 touch a.file
684	atf_check -e empty -o empty -s exit:0 chown $nobody_uid:$daemon_gid a.file
685
686	atf_check -e empty \
687	    -o match:'\-rw\-r\-\-r\-\-[[:space:]]+1[[:space:]]+'"$nobody_uid[[:space:]]+$daemon_gid"'[[:space:]]+.+a\.file' \
688	    ls -ln a.file
689
690}
691
692atf_test_case o_flag
693o_flag_head()
694{
695	atf_set "descr" "Verify that the output from ls -o prints out the chflag values or '-' if none are set"
696	atf_set "require.user" "root"
697}
698
699o_flag_body()
700{
701	local size=12345
702
703	create_test_dir
704
705	atf_check -e ignore -o empty -s exit:0 dd if=/dev/zero of=a.file \
706	    bs=$size count=1
707	atf_check -e ignore -o empty -s exit:0 dd if=/dev/zero of=b.file \
708	    bs=$size count=1
709	atf_check -e empty -o empty -s exit:0 chflags uarch a.file
710
711	atf_check -e empty -o match:"[[:space:]]+uarch[[:space:]]$size+.+a\\.file" \
712	    -s exit:0 ls -lo a.file
713	atf_check -e empty -o match:"[[:space:]]+\\-[[:space:]]$size+.+b\\.file" \
714	    -s exit:0 ls -lo b.file
715}
716
717atf_test_case p_flag
718p_flag_head()
719{
720	atf_set "descr" "Verify that the output from ls -p prints out '/' after directories"
721}
722
723p_flag_body()
724{
725	create_test_inputs
726
727	paths=$(find -L .)
728	[ -n "$paths" ] || atf_skip 'Could not find any paths to iterate over (!)'
729
730	for path in $paths; do
731		suffix=
732		# If path is not a symlink and is a directory, then the suffix
733		# must be "/".
734		if [ ! -L "${path}" -a -d "$path" ]; then
735			suffix=/
736		fi
737		atf_check -e empty -o match:"$path${suffix}" -s exit:0 \
738		    ls -dp $path
739	done
740}
741
742atf_test_case q_flag_and_w_flag
743q_flag_and_w_flag_head()
744{
745	atf_set "descr" "Verify that the output from ls -q prints out '?' for ESC and ls -w prints out the escape character"
746}
747
748q_flag_and_w_flag_body()
749{
750	atf_skip "kyua report-jenkins doesn't properly escape non-printable chars: https://github.com/jmmv/kyua/issues/136"
751
752	create_test_dir
753
754	test_file="$(printf "y\01z")"
755
756	atf_check -e empty -o empty -s exit:0 touch "$test_file"
757
758	atf_check -e empty -o match:'y\?z' -s exit:0 ls -q "$test_file"
759	atf_check -e empty -o match:"$test_file" -s exit:0 ls -w "$test_file"
760}
761
762atf_test_case r_flag
763r_flag_head()
764{
765	atf_set "descr" "Verify that the output from ls -r sorts the same way as reverse sorting with sort(1)"
766}
767
768r_flag_body()
769{
770	create_test_inputs
771
772	WITH_r=$PWD/../with_r.out
773	WITH_sort=$PWD/../with_sort.out
774
775	atf_check -e empty -o save:$WITH_r -s exit:0 ls -1r
776	atf_check -e empty -o save:$WITH_sort -s exit:0 sh -c 'ls -1 | sort -r'
777
778	echo "Sorted with -r"
779	cat $WITH_r
780	echo "Reverse sorted with sort(1)"
781	cat $WITH_sort
782
783	atf_check_equal "$(cat $WITH_r)" "$(cat $WITH_sort)"
784}
785
786atf_test_case s_flag
787s_flag_head()
788{
789	atf_set "descr" "Verify that the output from ls -s matches the output from stat(1)"
790}
791
792s_flag_body()
793{
794	create_test_inputs2
795	for file in $files; do
796		atf_check -e empty \
797		    -o match:"$(stat -f "%b" $file)[[:space:]]+$file" ls -s $file
798	done
799}
800
801atf_test_case t_flag
802t_flag_head()
803{
804	atf_set "descr" "Verify that the output from ls -t sorts by modification time"
805}
806
807t_flag_body()
808{
809	create_test_dir
810
811	atf_check -e empty -o empty -s exit:0 touch a.file
812	atf_check -e empty -o empty -s exit:0 touch b.file
813
814	atf_check -e empty -o match:'a\.file' -s exit:0 sh -c 'ls -lt | tail -n 1'
815	atf_check -e empty -o match:'b\.file.*a\.file' -s exit:0 ls -Ct
816
817	atf_check -e empty -o empty -s exit:0 rm a.file
818	atf_check -e empty -o empty -s exit:0 sh -c 'echo "i am a" > a.file'
819
820	atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lt | tail -n 1'
821	atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Ct
822}
823
824atf_test_case u_flag
825u_flag_head()
826{
827	atf_set "descr" "Verify that the output from ls -u sorts by last access"
828}
829
830u_flag_body()
831{
832	create_test_dir
833
834	atf_check -e empty -o empty -s exit:0 touch a.file
835	atf_check -e empty -o empty -s exit:0 touch b.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	atf_check -e empty -o empty -s exit:0 sh -c 'echo "i am a" > a.file'
841	atf_check -e empty -o match:'i am a' -s exit:0 cat a.file
842
843	atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lu | tail -n 1'
844	atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Cu
845}
846
847atf_test_case x_flag
848x_flag_head()
849{
850	atf_set "descr" "Verify that the output from ls -x is multi-column, sorted across"
851}
852
853x_flag_body()
854{
855	create_test_inputs
856
857	WITH_x=$PWD/../with_x.out
858
859	atf_check -e empty -o save:$WITH_x -s exit:0 ls -x
860
861	echo "With -x usage"
862	cat $WITH_x
863
864	atf_check -e ignore -o not-empty -s exit:0 \
865	    egrep "a[[:space:]]+c[[:space:]]+d[[:space:]]+e[[:space:]]+h" $WITH_x
866	atf_check -e ignore -o not-empty -s exit:0 \
867	    egrep "i[[:space:]]+klmn[[:space:]]+opqr[[:space:]]+stuv[[:space:]]+wxyz" $WITH_x
868}
869
870atf_test_case y_flag
871y_flag_head()
872{
873	atf_set "descr" "Verify that the output from ls -y sorts the same way as sort(1)"
874}
875
876y_flag_body()
877{
878	create_test_inputs
879
880	WITH_sort=$PWD/../with_sort.out
881	WITH_y=$PWD/../with_y.out
882
883	atf_check -e empty -o save:$WITH_sort -s exit:0 sh -c 'ls -1 | sort'
884	atf_check -e empty -o save:$WITH_y -s exit:0 ls -1y
885
886	echo "Sorted with sort(1)"
887	cat $WITH_sort
888	echo "Sorted with -y"
889	cat $WITH_y
890
891	atf_check_equal "$(cat $WITH_sort)" "$(cat $WITH_y)"
892}
893
894atf_test_case 1_flag
8951_flag_head()
896{
897	atf_set "descr" "Verify that -1 prints out one item per line"
898}
899
9001_flag_body()
901{
902	create_test_inputs
903
904	WITH_1=$PWD/../with_1.out
905	WITHOUT_1=$PWD/../without_1.out
906
907	atf_check -e empty -o save:$WITH_1 -s exit:0 ls -1
908	atf_check -e empty -o save:$WITHOUT_1 -s exit:0 \
909		sh -c 'for i in $(ls); do echo $i; done'
910
911	echo "Explicit -1 usage"
912	cat $WITH_1
913	echo "No -1 usage"
914	cat $WITHOUT_1
915
916	atf_check_equal "$(cat $WITH_1)" "$(cat $WITHOUT_1)"
917}
918
919atf_init_test_cases()
920{
921	export BLOCKSIZE=512
922
923	atf_add_test_case A_flag
924	atf_add_test_case A_flag_implied_when_root
925	atf_add_test_case B_flag
926	atf_add_test_case C_flag
927	atf_add_test_case D_flag
928	atf_add_test_case F_flag
929	#atf_add_test_case G_flag
930	atf_add_test_case H_flag
931	atf_add_test_case I_flag
932	atf_add_test_case I_flag_voids_implied_A_flag_when_root
933	atf_add_test_case L_flag
934	#atf_add_test_case P_flag
935	atf_add_test_case R_flag
936	atf_add_test_case S_flag
937	atf_add_test_case T_flag
938	#atf_add_test_case U_flag
939	#atf_add_test_case W_flag
940	#atf_add_test_case Z_flag
941	atf_add_test_case a_flag
942	atf_add_test_case b_flag
943	#atf_add_test_case c_flag
944	atf_add_test_case d_flag
945	atf_add_test_case f_flag
946	atf_add_test_case g_flag
947	atf_add_test_case h_flag
948	atf_add_test_case i_flag
949	atf_add_test_case k_flag
950	atf_add_test_case l_flag
951	atf_add_test_case lcomma_flag
952	atf_add_test_case m_flag
953	atf_add_test_case n_flag
954	atf_add_test_case o_flag
955	atf_add_test_case p_flag
956	atf_add_test_case q_flag_and_w_flag
957	atf_add_test_case r_flag
958	atf_add_test_case s_flag
959	atf_add_test_case t_flag
960	atf_add_test_case u_flag
961	atf_add_test_case x_flag
962	atf_add_test_case y_flag
963	atf_add_test_case 1_flag
964}
965