2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU Lesser General Public License as published by
6 ** the Free Software Foundation; either version 2.1 of the License, or
7 ** (at your option) any later version.
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ** GNU Lesser General Public License for more details.
14 ** You should have received a copy of the GNU Lesser General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include "test_main.h"
36 static void make_data (int *data
, int len
, int seed
) ;
38 static void file_open_test (const char *filename
) ;
39 static void file_read_write_test (const char *filename
) ;
40 static void file_truncate_test (const char *filename
) ;
42 static void test_open_or_die (SF_PRIVATE
*psf
, int linenum
) ;
43 static void test_close_or_die (SF_PRIVATE
*psf
, int linenum
) ;
45 static void test_write_or_die (SF_PRIVATE
*psf
, void *data
, sf_count_t bytes
, sf_count_t items
, sf_count_t new_position
, int linenum
) ;
46 static void test_read_or_die (SF_PRIVATE
*psf
, void *data
, sf_count_t bytes
, sf_count_t items
, sf_count_t new_position
, int linenum
) ;
47 static void test_equal_or_die (int *array1
, int *array2
, int len
, int linenum
) ;
48 static void test_seek_or_die (SF_PRIVATE
*psf
, sf_count_t offset
, int whence
, sf_count_t new_position
, int linenum
) ;
52 /*==============================================================================
53 ** Actual test functions.
57 file_open_test (const char *filename
)
58 { SF_PRIVATE sf_data
, *psf
;
61 print_test_name ("Testing file open") ;
63 memset (&sf_data
, 0, sizeof (sf_data
)) ;
66 /* Ensure that the file doesn't already exist. */
67 if (unlink (filename
) != 0 && errno
!= ENOENT
)
68 { printf ("\n\nLine %d: unlink failed (%d) : %s\n\n", __LINE__
, errno
, strerror (errno
)) ;
72 psf
->file
.mode
= SFM_READ
;
73 snprintf (psf
->file
.path
.c
, sizeof (psf
->file
.path
.c
), "%s", filename
) ;
75 /* Test that open for read fails if the file doesn't exist. */
76 error
= psf_fopen (psf
) ;
78 { printf ("\n\nLine %d: psf_fopen() should have failed.\n\n", __LINE__
) ;
82 /* Reset error to zero. */
83 psf
->error
= SFE_NO_ERROR
;
85 /* Test file open in write mode. */
86 psf
->file
.mode
= SFM_WRITE
;
87 test_open_or_die (psf
, __LINE__
) ;
89 test_close_or_die (psf
, __LINE__
) ;
91 unlink (psf
->file
.path
.c
) ;
93 /* Test file open in read/write mode for a non-existant file. */
94 psf
->file
.mode
= SFM_RDWR
;
95 test_open_or_die (psf
, __LINE__
) ;
97 test_close_or_die (psf
, __LINE__
) ;
99 /* Test file open in read/write mode for an existing file. */
100 psf
->file
.mode
= SFM_RDWR
;
101 test_open_or_die (psf
, __LINE__
) ;
103 test_close_or_die (psf
, __LINE__
) ;
105 unlink (psf
->file
.path
.c
) ;
107 } /* file_open_test */
110 file_read_write_test (const char *filename
)
111 { static int data_out
[512] ;
112 static int data_in
[512] ;
114 SF_PRIVATE sf_data
, *psf
;
118 ** Open a new file and write two blocks of data to the file. After each
119 ** write, test that psf_get_filelen() returns the new length.
122 print_test_name ("Testing file write") ;
124 memset (&sf_data
, 0, sizeof (sf_data
)) ;
126 snprintf (psf
->file
.path
.c
, sizeof (psf
->file
.path
.c
), "%s", filename
) ;
128 /* Test file open in write mode. */
129 psf
->file
.mode
= SFM_WRITE
;
130 test_open_or_die (psf
, __LINE__
) ;
132 make_data (data_out
, ARRAY_LEN (data_out
), 1) ;
133 test_write_or_die (psf
, data_out
, sizeof (data_out
[0]), ARRAY_LEN (data_out
), sizeof (data_out
), __LINE__
) ;
135 if ((retval
= psf_get_filelen (psf
)) != sizeof (data_out
))
136 { printf ("\n\nLine %d: file length after write is not correct (%" PRId64
" should be %zd).\n\n", __LINE__
, retval
, sizeof (data_out
)) ;
138 printf ("An fsync() may be necessary before fstat() in psf_get_filelen().\n\n") ;
142 make_data (data_out
, ARRAY_LEN (data_out
), 2) ;
143 test_write_or_die (psf
, data_out
, ARRAY_LEN (data_out
), sizeof (data_out
[0]), 2 * sizeof (data_out
), __LINE__
) ;
145 if ((retval
= psf_get_filelen (psf
)) != 2 * sizeof (data_out
))
146 { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64
" should be %zd)\n\n", __LINE__
, retval
, 2 * sizeof (data_out
)) ;
150 test_close_or_die (psf
, __LINE__
) ;
154 ** Now open the file in read mode, check the file length and check
155 ** that the data is correct.
158 print_test_name ("Testing file read") ;
160 /* Test file open in write mode. */
161 psf
->file
.mode
= SFM_READ
;
162 test_open_or_die (psf
, __LINE__
) ;
164 make_data (data_out
, ARRAY_LEN (data_out
), 1) ;
165 test_read_or_die (psf
, data_in
, 1, sizeof (data_in
), sizeof (data_in
), __LINE__
) ;
166 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
168 make_data (data_out
, ARRAY_LEN (data_out
), 2) ;
169 test_read_or_die (psf
, data_in
, sizeof (data_in
[0]), ARRAY_LEN (data_in
), 2 * sizeof (data_in
), __LINE__
) ;
170 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
172 test_close_or_die (psf
, __LINE__
) ;
177 ** Open the file in read/write mode, seek around a bit and then seek to
178 ** the end of the file and write another block of data (3rd block). Then
179 ** go back and check that all three blocks are correct.
182 print_test_name ("Testing file seek") ;
184 /* Test file open in read/write mode. */
185 psf
->file
.mode
= SFM_RDWR
;
186 test_open_or_die (psf
, __LINE__
) ;
188 test_seek_or_die (psf
, 0, SEEK_SET
, 0, __LINE__
) ;
189 test_seek_or_die (psf
, 0, SEEK_END
, 2 * SIGNED_SIZEOF (data_out
), __LINE__
) ;
190 test_seek_or_die (psf
, -1 * SIGNED_SIZEOF (data_out
), SEEK_CUR
, (sf_count_t
) sizeof (data_out
), __LINE__
) ;
192 test_seek_or_die (psf
, SIGNED_SIZEOF (data_out
), SEEK_CUR
, 2 * SIGNED_SIZEOF (data_out
), __LINE__
) ;
193 make_data (data_out
, ARRAY_LEN (data_out
), 3) ;
194 test_write_or_die (psf
, data_out
, sizeof (data_out
[0]), ARRAY_LEN (data_out
), 3 * sizeof (data_out
), __LINE__
) ;
196 test_seek_or_die (psf
, 0, SEEK_SET
, 0, __LINE__
) ;
197 make_data (data_out
, ARRAY_LEN (data_out
), 1) ;
198 test_read_or_die (psf
, data_in
, 1, sizeof (data_in
), sizeof (data_in
), __LINE__
) ;
199 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
201 test_seek_or_die (psf
, 2 * SIGNED_SIZEOF (data_out
), SEEK_SET
, 2 * SIGNED_SIZEOF (data_out
), __LINE__
) ;
202 make_data (data_out
, ARRAY_LEN (data_out
), 3) ;
203 test_read_or_die (psf
, data_in
, 1, sizeof (data_in
), 3 * sizeof (data_in
), __LINE__
) ;
204 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
206 test_seek_or_die (psf
, SIGNED_SIZEOF (data_out
), SEEK_SET
, SIGNED_SIZEOF (data_out
), __LINE__
) ;
207 make_data (data_out
, ARRAY_LEN (data_out
), 2) ;
208 test_read_or_die (psf
, data_in
, 1, sizeof (data_in
), 2 * sizeof (data_in
), __LINE__
) ;
209 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
211 test_close_or_die (psf
, __LINE__
) ;
215 ** Now test operations with a non-zero psf->fileoffset field. This field
216 ** sets an artificial file start positions so that a seek to the start of
217 ** the file will actually be a seek to the value given by psf->fileoffset.
220 print_test_name ("Testing file offset") ;
222 /* Test file open in read/write mode. */
223 psf
->file
.mode
= SFM_RDWR
;
224 psf
->fileoffset
= sizeof (data_out
[0]) * ARRAY_LEN (data_out
) ;
225 test_open_or_die (psf
, __LINE__
) ;
227 if ((retval
= psf_get_filelen (psf
)) != 3 * sizeof (data_out
))
228 { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64
" should be %zd)\n\n", __LINE__
, retval
, 3 * sizeof (data_out
)) ;
232 test_seek_or_die (psf
, SIGNED_SIZEOF (data_out
), SEEK_SET
, SIGNED_SIZEOF (data_out
), __LINE__
) ;
233 make_data (data_out
, ARRAY_LEN (data_out
), 5) ;
234 test_write_or_die (psf
, data_out
, sizeof (data_out
[0]), ARRAY_LEN (data_out
), 2 * sizeof (data_out
), __LINE__
) ;
235 test_close_or_die (psf
, __LINE__
) ;
237 /* final test with psf->fileoffset == 0. */
239 psf
->file
.mode
= SFM_RDWR
;
240 psf
->fileoffset
= 0 ;
241 test_open_or_die (psf
, __LINE__
) ;
243 if ((retval
= psf_get_filelen (psf
)) != 3 * sizeof (data_out
))
244 { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64
" should be %zd)\n\n", __LINE__
, retval
, 3 * sizeof (data_out
)) ;
248 make_data (data_out
, ARRAY_LEN (data_out
), 1) ;
249 test_read_or_die (psf
, data_in
, 1, sizeof (data_in
), sizeof (data_in
), __LINE__
) ;
250 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
252 make_data (data_out
, ARRAY_LEN (data_out
), 2) ;
253 test_read_or_die (psf
, data_in
, 1, sizeof (data_in
), 2 * sizeof (data_in
), __LINE__
) ;
254 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
256 make_data (data_out
, ARRAY_LEN (data_out
), 5) ;
257 test_read_or_die (psf
, data_in
, 1, sizeof (data_in
), 3 * sizeof (data_in
), __LINE__
) ;
258 test_equal_or_die (data_out
, data_in
, ARRAY_LEN (data_out
), __LINE__
) ;
260 test_close_or_die (psf
, __LINE__
) ;
263 } /* file_read_write_test */
266 file_truncate_test (const char *filename
)
267 { SF_PRIVATE sf_data
, *psf
;
268 unsigned char buffer
[256] ;
272 ** Open a new file and write two blocks of data to the file. After each
273 ** write, test that psf_get_filelen() returns the new length.
276 print_test_name ("Testing file truncate") ;
278 memset (&sf_data
, 0, sizeof (sf_data
)) ;
279 memset (buffer
, 0xEE, sizeof (buffer
)) ;
282 snprintf (psf
->file
.path
.c
, sizeof (psf
->file
.path
.c
), "%s", filename
) ;
285 ** Open the file write mode, write 0xEE data and then extend the file
286 ** using truncate (the extended data should be 0x00).
288 psf
->file
.mode
= SFM_WRITE
;
289 test_open_or_die (psf
, __LINE__
) ;
290 test_write_or_die (psf
, buffer
, sizeof (buffer
) / 2, 1, sizeof (buffer
) / 2, __LINE__
) ;
291 psf_ftruncate (psf
, sizeof (buffer
)) ;
292 test_close_or_die (psf
, __LINE__
) ;
294 /* Open the file in read mode and check the data. */
295 psf
->file
.mode
= SFM_READ
;
296 test_open_or_die (psf
, __LINE__
) ;
297 test_read_or_die (psf
, buffer
, sizeof (buffer
), 1, sizeof (buffer
), __LINE__
) ;
298 test_close_or_die (psf
, __LINE__
) ;
300 for (k
= 0 ; k
< SIGNED_SIZEOF (buffer
) / 2 ; k
++)
301 if (buffer
[k
] != 0xEE)
302 { printf ("\n\nLine %d : buffer [%d] = %d (should be 0xEE)\n\n", __LINE__
, k
, buffer
[k
]) ;
306 for (k
= SIGNED_SIZEOF (buffer
) / 2 ; k
< SIGNED_SIZEOF (buffer
) ; k
++)
308 { printf ("\n\nLine %d : buffer [%d] = %d (should be 0)\n\n", __LINE__
, k
, buffer
[k
]) ;
312 /* Open the file in read/write and shorten the file using truncate. */
313 psf
->file
.mode
= SFM_RDWR
;
314 test_open_or_die (psf
, __LINE__
) ;
315 psf_ftruncate (psf
, sizeof (buffer
) / 4) ;
316 test_close_or_die (psf
, __LINE__
) ;
318 /* Check the file length. */
319 psf
->file
.mode
= SFM_READ
;
320 test_open_or_die (psf
, __LINE__
) ;
321 test_seek_or_die (psf
, 0, SEEK_END
, SIGNED_SIZEOF (buffer
) / 4, __LINE__
) ;
322 test_close_or_die (psf
, __LINE__
) ;
325 } /* file_truncate_test */
327 /*==============================================================================
328 ** Testing helper functions.
332 test_open_or_die (SF_PRIVATE
*psf
, int linenum
)
335 /* Test that open for read fails if the file doesn't exist. */
336 error
= psf_fopen (psf
) ;
338 { printf ("\n\nLine %d: psf_fopen() failed : %s\n\n", linenum
, strerror (errno
)) ;
342 } /* test_open_or_die */
345 test_close_or_die (SF_PRIVATE
*psf
, int linenum
)
348 if (psf_file_valid (psf
))
349 { printf ("\n\nLine %d: psf->file.filedes should not be valid.\n\n", linenum
) ;
353 } /* test_close_or_die */
356 test_write_or_die (SF_PRIVATE
*psf
, void *data
, sf_count_t bytes
, sf_count_t items
, sf_count_t new_position
, int linenum
)
357 { sf_count_t retval
;
359 retval
= psf_fwrite (data
, bytes
, items
, psf
) ;
361 { printf ("\n\nLine %d: psf_write() returned %" PRId64
" (should be %" PRId64
")\n\n", linenum
, retval
, items
) ;
365 if ((retval
= psf_ftell (psf
)) != new_position
)
366 { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64
" should be %" PRId64
")\n\n", linenum
, retval
, new_position
) ;
371 } /* test_write_or_die */
374 test_read_or_die (SF_PRIVATE
*psf
, void *data
, sf_count_t bytes
, sf_count_t items
, sf_count_t new_position
, int linenum
)
375 { sf_count_t retval
;
377 retval
= psf_fread (data
, bytes
, items
, psf
) ;
379 { printf ("\n\nLine %d: psf_write() returned %" PRId64
" (should be %" PRId64
")\n\n", linenum
, retval
, items
) ;
383 if ((retval
= psf_ftell (psf
)) != new_position
)
384 { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64
" should be %" PRId64
")\n\n", linenum
, retval
, new_position
) ;
389 } /* test_write_or_die */
392 test_seek_or_die (SF_PRIVATE
*psf
, sf_count_t offset
, int whence
, sf_count_t new_position
, int linenum
)
393 { sf_count_t retval
;
395 retval
= psf_fseek (psf
, offset
, whence
) ;
397 if (retval
!= new_position
)
398 { printf ("\n\nLine %d: psf_fseek() failed. New position is %" PRId64
" (should be %" PRId64
").\n\n",
399 linenum
, retval
, new_position
) ;
403 } /* test_seek_or_die */
406 test_equal_or_die (int *array1
, int *array2
, int len
, int linenum
)
409 for (k
= 0 ; k
< len
; k
++)
410 if (array1
[k
] != array2
[k
])
411 printf ("\n\nLine %d: error at index %d (%d != %d).\n\n",
412 linenum
, k
, array1
[k
], array2
[k
]) ;
415 } /* test_equal_or_die */
418 make_data (int *data
, int len
, int seed
)
421 srand (seed
* 3333333 + 14756123) ;
423 for (k
= 0 ; k
< len
; k
++)
430 { const char *filename
= "file_io.dat" ;
432 file_open_test (filename
) ;
433 file_read_write_test (filename
) ;
434 file_truncate_test (filename
) ;