1#
2# Copyright 2014, Google Inc. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met:
7#
8# * Redistributions of source code must retain the above copyright
9#   notice, this list of conditions and the following disclaimer.
10# * 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# * Neither the name of Google Inc. nor the names of its
14#   contributors may be used to endorse or promote products derived from
15#   this software without specific written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29#
30
31# Helper function that is always used to create and fill stderr.txt for these
32# tests.
33_custom_create_file()
34{
35	# The first argument is a command.
36	# The second is just a string.
37	case "${1}" in
38		creat) > stderr.txt ;;
39		print) [ "${2}" ] && \
40		    printf "%s\n" "${2}" >> stderr.txt ;;
41	esac
42}
43
44# Helper function that create the file stderr.txt that contains the string
45# passed in as the first argument.
46create_stderr_file()
47{
48	_custom_create_file creat
49	_custom_create_file print "${1}"
50}
51
52# Helper function that create the file stderr.txt that contains the expected
53# truncate utility usage message.
54create_stderr_usage_file()
55{
56	_custom_create_file creat
57	_custom_create_file print "${1}"
58	_custom_create_file print \
59	    "usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ..."
60	_custom_create_file print "       truncate [-c] -r rfile file ..."
61	_custom_create_file print "       truncate [-c] -d [-o offset[K|k|M|m|G|g|T|t]] -l length[K|k|M|m|G|g|T|t] file ..."
62}
63
64atf_test_case illegal_option
65illegal_option_head()
66{
67	atf_set "descr" "Verifies that truncate exits >0 when passed an" \
68	    "invalid command line option"
69}
70illegal_option_body()
71{
72	create_stderr_usage_file 'truncate: illegal option -- 7'
73
74	# We expect the error message, with no new files.
75	atf_check -s not-exit:0 -e file:stderr.txt truncate -7 -s0 output.txt
76	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
77}
78
79atf_test_case illegal_size
80illegal_size_head()
81{
82	atf_set "descr" "Verifies that truncate exits >0 when passed an" \
83	    "invalid power of two convention"
84}
85illegal_size_body()
86{
87	create_stderr_file "truncate: invalid size argument \`+1L'"
88
89	# We expect the error message, with no new files.
90	atf_check -s not-exit:0 -e file:stderr.txt truncate -s+1L output.txt
91	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
92}
93
94atf_test_case too_large_size
95too_large_size_head()
96{
97	atf_set "descr" "Verifies that truncate exits >0 when passed an" \
98	    "a size that is INT64_MAX < size <= UINT64_MAX"
99}
100too_large_size_body()
101{
102	create_stderr_file "truncate: invalid size argument \`8388608t'"
103
104	# We expect the error message, with no new files.
105	atf_check -s not-exit:0 -e file:stderr.txt \
106	    truncate -s8388608t output.txt
107	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
108}
109
110atf_test_case opt_c
111opt_c_head()
112{
113	atf_set "descr" "Verifies that -c prevents creation of new files"
114}
115opt_c_body()
116{
117	# No new files and truncate returns 0 as if this is a success.
118	atf_check truncate -c -s 0 doesnotexist.txt
119	[ ! -e output.txt ] || atf_fail "doesnotexist.txt should not exist"
120	> reference
121	atf_check truncate -c -r reference doesnotexist.txt
122	[ ! -e output.txt ] || atf_fail "doesnotexist.txt should not exist"
123
124	create_stderr_file
125
126	# The existing file will be altered by truncate.
127	> exists.txt
128	atf_check -e file:stderr.txt truncate -c -s1 exists.txt
129	[ -s exists.txt ] || atf_fail "exists.txt be larger than zero bytes"
130}
131
132atf_test_case opt_rs
133opt_rs_head()
134{
135	atf_set "descr" "Verifies that truncate command line flags" \
136	    "-s and -r cannot be specifed together"
137}
138opt_rs_body()
139{
140	create_stderr_usage_file
141
142	# Force an error due to the use of both -s and -r.
143	> afile
144	atf_check -s not-exit:0 -e file:stderr.txt truncate -s0 -r afile afile
145}
146
147atf_test_case no_files
148no_files_head()
149{
150	atf_set "descr" "Verifies that truncate needs a list of files on" \
151	    "the command line"
152}
153no_files_body()
154{
155	create_stderr_usage_file
156
157	# A list of files must be present on the command line.
158	atf_check -s not-exit:0 -e file:stderr.txt truncate -s1
159}
160
161atf_test_case bad_refer
162bad_refer_head()
163{
164	atf_set "descr" "Verifies that truncate detects a non-existent" \
165	    "reference file"
166}
167bad_refer_body()
168{
169	create_stderr_file "truncate: afile: No such file or directory"
170
171	# The reference file must exist before you try to use it.
172	atf_check -s not-exit:0 -e file:stderr.txt truncate -r afile afile
173	[ ! -e afile ] || atf_fail "afile should not exist"
174}
175
176atf_test_case bad_truncate
177bad_truncate_head()
178{
179	atf_set "descr" "Verifies that truncate reports an error during" \
180	    "truncation"
181	atf_set "require.user" "unprivileged"
182}
183bad_truncate_body()
184{
185	create_stderr_file "truncate: exists.txt: Permission denied"
186
187	# Trying to get the ftruncate() call to return -1.
188	> exists.txt
189	atf_check chmod 444 exists.txt
190
191	atf_check -s not-exit:0 -e file:stderr.txt truncate -s1 exists.txt
192}
193
194atf_test_case new_absolute_grow
195new_absolute_grow_head()
196{
197	atf_set "descr" "Verifies truncate can make and grow a new 1m file"
198}
199new_absolute_grow_body()
200{
201	create_stderr_file
202
203	# Create a new file and grow it to 1024 bytes.
204	atf_check -s exit:0 -e file:stderr.txt truncate -s1k output.txt
205	atf_check -s exit:1 cmp -s output.txt /dev/zero
206	eval $(stat -s output.txt)
207	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
208
209	create_stderr_file
210
211	# Grow the existing file to 1M.  We are using absolute sizes.
212	atf_check -s exit:0 -e file:stderr.txt truncate -c -s1M output.txt
213	atf_check -s exit:1 cmp -s output.txt /dev/zero
214	eval $(stat -s output.txt)
215	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
216}
217
218atf_test_case new_absolute_shrink
219new_absolute_shrink_head()
220{
221	atf_set "descr" "Verifies that truncate can make and" \
222	    "shrink a new 1m file"
223}
224new_absolute_shrink_body()
225{
226	create_stderr_file
227
228	# Create a new file and grow it to 1048576 bytes.
229	atf_check -s exit:0 -e file:stderr.txt truncate -s1M output.txt
230	atf_check -s exit:1 cmp -s output.txt /dev/zero
231	eval $(stat -s output.txt)
232	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
233
234	create_stderr_file
235
236	# Shrink the existing file to 1k.  We are using absolute sizes.
237	atf_check -s exit:0 -e file:stderr.txt truncate -s1k output.txt
238	atf_check -s exit:1 cmp -s output.txt /dev/zero
239	eval $(stat -s output.txt)
240	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
241}
242
243atf_test_case new_relative_grow
244new_relative_grow_head()
245{
246	atf_set "descr" "Verifies truncate can make and grow a new 1m file" \
247	    "using relative sizes"
248}
249new_relative_grow_body()
250{
251	create_stderr_file
252
253	# Create a new file and grow it to 1024 bytes.
254	atf_check -s exit:0 -e file:stderr.txt truncate -s+1k output.txt
255	atf_check -s exit:1 cmp -s output.txt /dev/zero
256	eval $(stat -s output.txt)
257	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
258
259	create_stderr_file
260
261	# Grow the existing file to 1M.  We are using relative sizes.
262	atf_check -s exit:0 -e file:stderr.txt truncate -s+1047552 output.txt
263	atf_check -s exit:1 cmp -s output.txt /dev/zero
264	eval $(stat -s output.txt)
265	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
266}
267
268atf_test_case new_relative_shrink
269new_relative_shrink_head()
270{
271	atf_set "descr" "Verifies truncate can make and shrink a new 1m file" \
272	    "using relative sizes"
273}
274new_relative_shrink_body()
275{
276	create_stderr_file
277
278	# Create a new file and grow it to 1049600 bytes.
279	atf_check -s exit:0 -e file:stderr.txt truncate -s+1049600 output.txt
280	atf_check -s exit:1 cmp -s output.txt /dev/zero
281	eval $(stat -s output.txt)
282	[ ${st_size} -eq 1049600 ] || atf_fail "expected file size of 1m"
283
284	create_stderr_file
285
286	# Shrink the existing file to 1k.  We are using relative sizes.
287	atf_check -s exit:0 -e file:stderr.txt truncate -s-1M output.txt
288	atf_check -s exit:1 cmp -s output.txt /dev/zero
289	eval $(stat -s output.txt)
290	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
291}
292
293atf_test_case cannot_open
294cannot_open_head()
295{
296	atf_set "descr" "Verifies truncate handles open failures correctly" \
297	    "in a list of files"
298	atf_set "require.user" "unprivileged"
299}
300cannot_open_body()
301{
302	# Create three files -- the middle file cannot allow writes.
303	> before
304	> 0000
305	> after
306	atf_check chmod 0000 0000
307
308	create_stderr_file "truncate: 0000: Permission denied"
309
310	# Create a new file and grow it to 1024 bytes.
311	atf_check -s not-exit:0 -e file:stderr.txt \
312	truncate -c -s1k before 0000 after
313	eval $(stat -s before)
314	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
315	eval $(stat -s after)
316	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
317	eval $(stat -s 0000)
318	[ ${st_size} -eq 0 ] || atf_fail "expected file size of zero"
319}
320
321atf_test_case reference
322reference_head()
323{
324	atf_set "descr" "Verifies that truncate can use a reference file"
325}
326reference_body()
327{
328	# Create a 4 byte reference file.
329	printf "123\n" > reference
330	eval $(stat -s reference)
331	[ ${st_size} -eq 4 ] || atf_fail "reference file should be 4 bytes"
332
333	create_stderr_file
334
335	# Create a new file and grow it to 4 bytes.
336	atf_check -e file:stderr.txt truncate -r reference afile
337	eval $(stat -s afile)
338	[ ${st_size} -eq 4 ] || atf_fail "new file should also be 4 bytes"
339}
340
341atf_test_case new_zero
342new_zero_head()
343{
344	atf_set "descr" "Verifies truncate can make and grow zero byte file"
345}
346new_zero_body()
347{
348	create_stderr_file
349
350	# Create a new file and grow it to zero bytes.
351	atf_check -s exit:0 -e file:stderr.txt truncate -s0 output.txt
352	eval $(stat -s output.txt)
353	[ ${st_size} -eq 0 ] || atf_fail "expected file size of zero"
354
355	# Pretend to grow the file.
356	atf_check -s exit:0 -e file:stderr.txt truncate -s+0 output.txt
357	eval $(stat -s output.txt)
358	[ ${st_size} -eq 0 ] || atf_fail "expected file size of zero"
359}
360
361atf_test_case negative
362negative_head()
363{
364	atf_set "descr" "Verifies truncate treats negative sizes as zero"
365}
366negative_body()
367{
368	# Create a 5 byte file.
369	printf "abcd\n" > afile
370	eval $(stat -s afile)
371	[ ${st_size} -eq 5 ] || atf_fail "afile file should be 5 bytes"
372
373	create_stderr_file
374
375	# Create a new file and do a 100 byte negative relative shrink.
376	atf_check -e file:stderr.txt truncate -s-100 afile
377	eval $(stat -s afile)
378	[ ${st_size} -eq 0 ] || atf_fail "new file should now be zero bytes"
379}
380
381atf_test_case roundup
382roundup_head()
383{
384	atf_set "descr" "Verifies truncate round up"
385}
386roundup_body()
387{
388	# Create a 5 byte file.
389	printf "abcd\n" > afile
390	eval $(stat -s afile)
391	[ ${st_size} -eq 5 ] || atf_fail "afile file should be 5 bytes"
392
393	create_stderr_file
394
395	# Create a new file and do a 100 byte roundup.
396	atf_check -e file:stderr.txt truncate -s%100 afile
397	eval $(stat -s afile)
398	[ ${st_size} -eq 100 ] || atf_fail "new file should now be 100 bytes"
399}
400
401atf_test_case rounddown
402rounddown_head()
403{
404	atf_set "descr" "Verifies truncate round down"
405}
406rounddown_body()
407{
408	# Create a 5 byte file.
409	printf "abcd\n" > afile
410	eval $(stat -s afile)
411	[ ${st_size} -eq 5 ] || atf_fail "afile file should be 5 bytes"
412
413	create_stderr_file
414
415	# Create a new file and do a 2 byte roundup.
416	atf_check -e file:stderr.txt truncate -s/2 afile
417	eval $(stat -s afile)
418	[ ${st_size} -eq 4 ] || atf_fail "new file should now be 4 bytes"
419}
420
421atf_test_case rounddown_zero
422rounddown_zero_head()
423{
424	atf_set "descr" "Verifies truncate round down to zero"
425}
426rounddown_zero_body()
427{
428	# Create a 5 byte file.
429	printf "abcd\n" > afile
430	eval $(stat -s afile)
431	[ ${st_size} -eq 5 ] || atf_fail "afile file should be 5 bytes"
432
433	create_stderr_file
434
435	# Create a new file and do a 10 byte roundup.
436	atf_check -e file:stderr.txt truncate -s/10 afile
437	eval $(stat -s afile)
438	[ ${st_size} -eq 0 ] || atf_fail "new file should now be 0 bytes"
439}
440
441atf_init_test_cases()
442{
443	atf_add_test_case illegal_option
444	atf_add_test_case illegal_size
445	atf_add_test_case too_large_size
446	atf_add_test_case opt_c
447	atf_add_test_case opt_rs
448	atf_add_test_case no_files
449	atf_add_test_case bad_refer
450	atf_add_test_case bad_truncate
451	atf_add_test_case cannot_open
452	atf_add_test_case new_absolute_grow
453	atf_add_test_case new_absolute_shrink
454	atf_add_test_case new_relative_grow
455	atf_add_test_case new_relative_shrink
456	atf_add_test_case reference
457	atf_add_test_case new_zero
458	atf_add_test_case negative
459	atf_add_test_case roundup
460	atf_add_test_case rounddown
461	atf_add_test_case rounddown_zero
462}
463