xref: /freebsd/bin/mv/tests/mv_test.sh (revision d4fb5984ab0b96cc784c907e622deda910d020f2)
1#
2# Copyright (c) 2007 Diomidis Spinellis
3# Copyright (c) 2023 Klara, Inc.
4#
5# SPDX-License-Identifier: BSD-2-Clause
6#
7
8mv_setup() {
9	atf_check mkdir fs
10	atf_check mount -t tmpfs -o size=1m tmp fs
11}
12
13mv_cleanup() {
14	umount fs || true
15}
16
17# Make a file that can later be verified
18mv_makefile() {
19	local cn="${1##*/}"
20	echo "$cn-$cn" >"$1"
21}
22
23# Verify that the file specified is correct
24mv_checkfile() {
25	atf_check -o inline:"$1-$1\n" cat "$2"
26}
27
28# Make a fifo that can later be verified
29mv_makepipe() {
30	atf_check mkfifo $1
31}
32
33# Verify that the file specified is correct
34mv_checkpipe() {
35	atf_check test -p "$2"
36}
37
38# Make a directory that can later be verified
39mv_makedir() {
40	local cn="${1##*/}"
41	atf_check mkdir -p "$1/$cn-$cn"
42}
43
44# Verify that the directory specified is correct
45mv_checkdir() {
46	atf_check test -d "$2/$1-$1"
47}
48
49# Verify that the specified file does not exist
50# (is not there)
51mv_checkabsent() {
52	atf_check -s exit:1 test -r "$1"
53}
54
55atf_test_case rename_file cleanup
56rename_file_head() {
57	atf_set "descr" "Rename file"
58	atf_set "require.user" "root"
59}
60rename_file_body() {
61	mv_setup
62	for FS in "" "fs/" ; do
63		mv_makefile fa
64		atf_check mv fa ${FS}fb
65		mv_checkfile fa ${FS}fb
66		mv_checkabsent fa
67	done
68}
69rename_file_cleanup() {
70	mv_cleanup
71}
72
73atf_test_case file_into_dir cleanup
74file_into_dir_head() {
75	atf_set "descr" "Move files into directory"
76	atf_set "require.user" "root"
77}
78file_into_dir_body() {
79	mv_setup
80	for FS in "" "fs/" ; do
81		mv_makefile fa
82		mv_makefile fb
83		atf_check mkdir -p ${FS}1/2/3
84		atf_check mv fa fb ${FS}1/2/3
85		mv_checkfile fa ${FS}1/2/3/fa
86		mv_checkfile fb ${FS}1/2/3/fb
87		mv_checkabsent fa
88		mv_checkabsent fb
89	done
90}
91file_into_dir_cleanup() {
92	mv_cleanup
93}
94
95atf_test_case file_from_dir cleanup
96file_from_dir_head() {
97	atf_set "descr" "Move file from directory to file"
98	atf_set "require.user" "root"
99}
100file_from_dir_body() {
101	mv_setup
102	atf_check mkdir -p 1/2/3
103	for FS in "" "fs/" ; do
104		mv_makefile 1/2/3/fa
105		atf_check mv 1/2/3/fa ${FS}fb
106		mv_checkfile fa ${FS}fb
107		mv_checkabsent 1/2/3/fa
108	done
109}
110file_from_dir_cleanup() {
111	mv_cleanup
112}
113
114atf_test_case file_from_dir_replace cleanup
115file_from_dir_replace_head() {
116	atf_set "descr" "Move file from directory to existing file"
117	atf_set "require.user" "root"
118}
119file_from_dir_replace_body() {
120	mv_setup
121	atf_check mkdir -p 1/2/3
122	for FS in "" "fs/" ; do
123		mv_makefile 1/2/3/fa
124		:> ${FS}fb
125		atf_check mv 1/2/3/fa ${FS}fb
126		mv_checkfile fa ${FS}fb
127		mv_checkabsent 1/2/3/fa
128	done
129}
130file_from_dir_replace_cleanup() {
131	mv_cleanup
132}
133
134atf_test_case file_to_dir cleanup
135file_to_dir_head() {
136	atf_set "descr" "Move file from directory to existing directory"
137	atf_set "require.user" "root"
138}
139file_to_dir_body() {
140	mv_setup
141	atf_check mkdir -p 1/2/3
142	for FS in "" "fs/" ; do
143		mv_makefile 1/2/3/fa
144		atf_check mkdir -p ${FS}db/fa
145		# Should fail per POSIX step 3a:
146		# Destination path is a file of type directory and
147		# source_file is not a file of type directory
148		atf_check -s not-exit:0 -e match:"Is a directory" \
149		      mv 1/2/3/fa ${FS}db
150		mv_checkfile fa 1/2/3/fa
151	done
152}
153file_to_dir_cleanup() {
154	mv_cleanup
155}
156
157atf_test_case file_from_rename_dir cleanup
158file_from_rename_dir_head() {
159	atf_set "descr" "Move file from directory to directory"
160	atf_set "require.user" "root"
161}
162file_from_rename_dir_body() {
163	mv_setup
164	atf_check mkdir -p da1/da2/da3
165	for FS in "" "fs/" ; do
166		atf_check mkdir -p ${FS}db1/db2/db3
167		mv_makefile da1/da2/da3/fa
168		atf_check mv da1/da2/da3/fa ${FS}db1/db2/db3/fb
169		mv_checkfile fa ${FS}db1/db2/db3/fb
170		mv_checkabsent da1/da2/da3/fa
171	done
172}
173file_from_rename_dir_cleanup() {
174	mv_cleanup
175}
176
177atf_test_case rename_dir cleanup
178rename_dir_head() {
179	atf_set "descr" "Rename directory"
180	atf_set "require.user" "root"
181}
182rename_dir_body() {
183	mv_setup
184	for FS in "" "fs/" ; do
185		mv_makedir da
186		atf_check mv da ${FS}db
187		mv_checkdir da ${FS}db
188		mv_checkabsent da
189	done
190}
191rename_dir_cleanup() {
192	mv_cleanup
193}
194
195atf_test_case dir_to_dir cleanup
196dir_to_dir_head() {
197	atf_set "descr" "Move directory to directory name"
198	atf_set "require.user" "root"
199}
200dir_to_dir_body() {
201	mv_setup
202	for FS in "" "fs/" ; do
203		mv_makedir da1/da2/da3/da
204		atf_check mkdir -p ${FS}db1/db2/db3
205		atf_check mv da1/da2/da3/da ${FS}db1/db2/db3/db
206		mv_checkdir da ${FS}db1/db2/db3/db
207		mv_checkabsent da1/da2/da3/da
208	done
209}
210dir_to_dir_cleanup() {
211	mv_cleanup
212}
213
214atf_test_case dir_into_dir cleanup
215dir_into_dir_head() {
216	atf_set "descr" "Move directory to directory"
217	atf_set "require.user" "root"
218}
219dir_into_dir_body() {
220	mv_setup
221	for FS in "" "fs/" ; do
222		mv_makedir da1/da2/da3/da
223		atf_check mkdir -p ${FS}db1/db2/db3
224		atf_check mv da1/da2/da3/da ${FS}db1/db2/db3
225		mv_checkdir da ${FS}db1/db2/db3/da
226		mv_checkabsent da1/da2/da3/da
227	done
228}
229dir_into_dir_cleanup() {
230	mv_cleanup
231}
232
233atf_test_case dir_to_empty_dir cleanup
234dir_to_empty_dir_head() {
235	atf_set "descr" "Move directory to existing empty directory"
236	atf_set "require.user" "root"
237}
238dir_to_empty_dir_body() {
239	mv_setup
240	for FS in "" "fs/" ; do
241		mv_makedir da1/da2/da3/da
242		atf_check mkdir -p ${FS}db1/db2/db3/da
243		atf_check mv da1/da2/da3/da ${FS}db1/db2/db3
244		mv_checkdir da ${FS}db1/db2/db3/da
245		mv_checkabsent da1/da2/da3/da
246	done
247}
248dir_to_empty_dir_cleanup() {
249	mv_cleanup
250}
251
252atf_test_case dir_to_nonempty_dir cleanup
253dir_to_nonempty_dir_head() {
254	atf_set "descr" "Move directory to existing non-empty directory"
255	atf_set "require.user" "root"
256}
257dir_to_nonempty_dir_body() {
258	mv_setup
259	for FS in "" "fs/" ; do
260		mv_makedir da1/da2/da3/da
261		atf_check mkdir -p ${FS}db1/db2/db3/da/full
262		# Should fail (per the semantics of rename(2))
263		atf_check -s not-exit:0 -e match:"Directory not empty" \
264		      mv da1/da2/da3/da ${FS}db1/db2/db3
265		mv_checkdir da da1/da2/da3/da
266	done
267}
268dir_to_nonempty_dir_cleanup() {
269	mv_cleanup
270}
271
272atf_test_case dir_to_file cleanup
273dir_to_file_head() {
274	atf_set "descr" "Move directory to existing file"
275	atf_set "require.user" "root"
276}
277dir_to_file_body() {
278	mv_setup
279	for FS in "" "fs/" ; do
280		mv_makedir da1/da2/da3/da
281		atf_check mkdir -p ${FS}db1/db2/db3
282		:> ${FS}db1/db2/db3/da
283		# Should fail per POSIX step 3b:
284		# Destination path is a file not of type directory
285		# and source_file is a file of type directory
286		atf_check -s not-exit:0 -e match:"Not a directory" \
287		      mv da1/da2/da3/da ${FS}db1/db2/db3/da
288		mv_checkdir da da1/da2/da3/da
289	done
290}
291dir_to_file_cleanup() {
292	mv_cleanup
293}
294
295atf_test_case rename_fifo cleanup
296rename_fifo_head() {
297	atf_set "descr" "Rename fifo"
298	atf_set "require.user" "root"
299}
300rename_fifo_body() {
301	mv_setup
302	for FS in "" "fs/" ; do
303		mv_makepipe fa
304		atf_check mv fa ${FS}fb
305		mv_checkpipe fa ${FS}fb
306		mv_checkabsent fa
307	done
308}
309rename_fifo_cleanup() {
310	mv_cleanup
311}
312
313atf_test_case fifo_into_dir cleanup
314fifo_into_dir_head() {
315	atf_set "descr" "Move fifos into directory"
316	atf_set "require.user" "root"
317}
318fifo_into_dir_body() {
319	mv_setup
320	for FS in "" "fs/" ; do
321		mv_makepipe fa
322		mv_makepipe fb
323		atf_check mkdir -p ${FS}1/2/3
324		atf_check mv fa fb ${FS}1/2/3
325		mv_checkpipe fa ${FS}1/2/3/fa
326		mv_checkpipe fb ${FS}1/2/3/fb
327		mv_checkabsent fa
328		mv_checkabsent fb
329	done
330}
331fifo_into_dir_cleanup() {
332	mv_cleanup
333}
334
335atf_test_case fifo_from_dir cleanup
336fifo_from_dir_head() {
337	atf_set "descr" "Move fifo from directory to fifo"
338	atf_set "require.user" "root"
339}
340fifo_from_dir_body() {
341	mv_setup
342	atf_check mkdir -p 1/2/3
343	for FS in "" "fs/" ; do
344		mv_makepipe 1/2/3/fa
345		atf_check mv 1/2/3/fa ${FS}fb
346		mv_checkpipe fa ${FS}fb
347		mv_checkabsent 1/2/3/fa
348	done
349}
350fifo_from_dir_cleanup() {
351	mv_cleanup
352}
353
354atf_test_case fifo_from_dir_into_dir cleanup
355fifo_from_dir_into_dir_head() {
356	atf_set "descr" "Move fifo from directory to directory"
357	atf_set "require.user" "root"
358}
359fifo_from_dir_into_dir_body() {
360	mv_setup
361	atf_check mkdir -p da1/da2/da3
362	for FS in "" "fs/" ; do
363		atf_check mkdir -p ${FS}db1/db2/db3
364		mv_makepipe da1/da2/da3/fa
365		atf_check mv da1/da2/da3/fa ${FS}db1/db2/db3/fb
366		mv_checkpipe fa ${FS}db1/db2/db3/fb
367		mv_checkabsent da1/da2/da3/fa
368	done
369}
370fifo_from_dir_into_dir_cleanup() {
371	mv_cleanup
372}
373
374atf_test_case mv_f cleanup
375mv_f_head() {
376	atf_set "descr" "Force replacement"
377	atf_set "require.user" "root"
378}
379mv_f_body() {
380	mv_setup
381	for FS in "" "fs/" ; do
382		mv_makefile fa
383		atf_check mv fa ${FS}fb
384		mv_checkfile fa ${FS}fb
385		mv_checkabsent fa
386		mv_makefile fa
387		:> ${FS}fb
388		atf_check mv -i -n -f fa ${FS}fb
389		mv_checkfile fa ${FS}fb
390		mv_checkabsent fa
391	done
392}
393mv_f_cleanup() {
394	mv_cleanup
395}
396
397atf_test_case mv_h cleanup
398mv_h_head() {
399	atf_set "descr" "Replace symbolic link"
400	atf_set "require.user" "root"
401}
402mv_h_body() {
403	mv_setup
404	for FS in "" "fs/" ; do
405		atf_check mkdir ${FS}da
406		atf_check ln -s da ${FS}db
407		# First test without -h, file goes into symlink target
408		mv_makefile fa
409		atf_check mv fa ${FS}db
410		mv_checkfile fa ${FS}da/fa
411		# Second test with -h, file replaces symlink
412		mv_makefile fa
413		atf_check mv -h fa ${FS}db
414		mv_checkfile fa ${FS}db
415	done
416}
417mv_h_cleanup() {
418	mv_cleanup
419}
420
421atf_test_case mv_i cleanup
422mv_i_head() {
423	atf_set "descr" "Confirm replacement"
424	atf_set "require.user" "root"
425}
426mv_i_body() {
427	mv_setup
428	echo n >n
429	echo y >y
430	for FS in "" "fs/" ; do
431		mv_makefile fa
432		mv_makefile ${FS}fb
433		# First test, answer no, file is not replaced
434		atf_check -e match:"^overwrite ${FS}fb\\?" \
435		      mv -i fa ${FS}fb <n
436		mv_checkfile fa fa
437		mv_checkfile fb ${FS}fb
438		# Second test, answer yes, file is replaced
439		atf_check -e match:"^overwrite ${FS}fb\\?" \
440		      mv -i fa ${FS}fb <y
441		mv_checkabsent fa
442		mv_checkfile fa ${FS}fb
443	done
444}
445mv_i_cleanup() {
446	mv_cleanup
447}
448
449atf_test_case mv_n cleanup
450mv_n_head() {
451	atf_set "descr" "Decline replacement"
452	atf_set "require.user" "root"
453}
454mv_n_body() {
455	mv_setup
456	for FS in "" "fs/" ; do
457		mv_makefile fa
458		mv_makefile ${FS}fb
459		atf_check mv -n fa ${FS}fb
460		mv_checkfile fa fa
461		mv_checkfile fb ${FS}fb
462	done
463}
464mv_n_cleanup() {
465	mv_cleanup
466}
467
468atf_test_case mv_v cleanup
469mv_v_head() {
470	atf_set "descr" "Verbose mode"
471	atf_set "require.user" "root"
472}
473mv_v_body() {
474	mv_setup
475	for FS in "" "fs/" ; do
476		mv_makefile fa
477		atf_check mkdir ${FS}da
478		atf_check -o inline:"fa -> ${FS}da/fa\n" \
479		      mv -v fa ${FS}da
480	done
481}
482mv_v_cleanup() {
483	mv_cleanup
484}
485
486atf_init_test_cases() {
487	atf_add_test_case rename_file
488	atf_add_test_case file_into_dir
489	atf_add_test_case file_from_dir
490	atf_add_test_case file_from_dir_replace
491	atf_add_test_case file_to_dir
492	atf_add_test_case file_from_rename_dir
493	atf_add_test_case rename_dir
494	atf_add_test_case dir_to_dir
495	atf_add_test_case dir_into_dir
496	atf_add_test_case dir_to_empty_dir
497	atf_add_test_case dir_to_nonempty_dir
498	atf_add_test_case dir_to_file
499	atf_add_test_case rename_fifo
500	atf_add_test_case fifo_into_dir
501	atf_add_test_case fifo_from_dir
502	atf_add_test_case fifo_from_dir_into_dir
503	atf_add_test_case mv_f
504	atf_add_test_case mv_h
505	atf_add_test_case mv_i
506	atf_add_test_case mv_n
507	atf_add_test_case mv_v
508}
509