bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / test / testfile.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_file_io.h"
18 #include "apr_file_info.h"
19 #include "apr_network_io.h"
20 #include "apr_errno.h"
21 #include "apr_general.h"
22 #include "apr_poll.h"
23 #include "apr_lib.h"
24 #include "test_apr.h"
25
26 #define DIRNAME "data"
27 #define FILENAME DIRNAME "/file_datafile.txt"
28 #define TESTSTR  "This is the file data file."
29
30 #define TESTREAD_BLKSIZE 1024
31 #define APR_BUFFERSIZE   4096 /* This should match APR's buffer size. */
32
33
34
35 static void test_open_noreadwrite(CuTest *tc)
36 {
37     apr_status_t rv;
38     apr_file_t *thefile = NULL;
39
40     rv = apr_file_open(&thefile, FILENAME,
41                        APR_CREATE | APR_EXCL, 
42                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
43     CuAssertTrue(tc, rv != APR_SUCCESS);
44     CuAssertIntEquals(tc, 1, APR_STATUS_IS_EACCES(rv));
45     CuAssertPtrEquals(tc, NULL, thefile); 
46 }
47
48 static void test_open_excl(CuTest *tc)
49 {
50     apr_status_t rv;
51     apr_file_t *thefile = NULL;
52
53     rv = apr_file_open(&thefile, FILENAME,
54                        APR_CREATE | APR_EXCL | APR_WRITE, 
55                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
56     CuAssertTrue(tc, rv != APR_SUCCESS);
57     CuAssertIntEquals(tc, 1, APR_STATUS_IS_EEXIST(rv));
58     CuAssertPtrEquals(tc, NULL, thefile); 
59 }
60
61 static void test_open_read(CuTest *tc)
62 {
63     apr_status_t rv;
64     apr_file_t *filetest = NULL;
65
66     rv = apr_file_open(&filetest, FILENAME, 
67                        APR_READ, 
68                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
69     CuAssertIntEquals(tc, APR_SUCCESS, rv);
70     CuAssertPtrNotNull(tc, filetest);
71     apr_file_close(filetest);
72 }
73
74 static void test_read(CuTest *tc)
75 {
76     apr_status_t rv;
77     apr_size_t nbytes = 256;
78     char *str = apr_pcalloc(p, nbytes + 1);
79     apr_file_t *filetest = NULL;
80     
81     rv = apr_file_open(&filetest, FILENAME, 
82                        APR_READ, 
83                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
84
85     apr_assert_success(tc, "Opening test file " FILENAME, rv);
86     rv = apr_file_read(filetest, str, &nbytes);
87     CuAssertIntEquals(tc, APR_SUCCESS, rv);
88     CuAssertIntEquals(tc, strlen(TESTSTR), nbytes);
89     CuAssertStrEquals(tc, TESTSTR, str);
90
91     apr_file_close(filetest);
92 }
93
94 static void test_filename(CuTest *tc)
95 {
96     const char *str;
97     apr_status_t rv;
98     apr_file_t *filetest = NULL;
99     
100     rv = apr_file_open(&filetest, FILENAME, 
101                        APR_READ, 
102                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
103     apr_assert_success(tc, "Opening test file " FILENAME, rv);
104
105     rv = apr_file_name_get(&str, filetest);
106     CuAssertIntEquals(tc, APR_SUCCESS, rv);
107     CuAssertStrEquals(tc, FILENAME, str);
108
109     apr_file_close(filetest);
110 }
111     
112 static void test_fileclose(CuTest *tc)
113 {
114     char str;
115     apr_status_t rv;
116     apr_size_t one = 1;
117     apr_file_t *filetest = NULL;
118     
119     rv = apr_file_open(&filetest, FILENAME, 
120                        APR_READ, 
121                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
122     apr_assert_success(tc, "Opening test file " FILENAME, rv);
123
124     rv = apr_file_close(filetest);
125     CuAssertIntEquals(tc, APR_SUCCESS, rv);
126     /* We just closed the file, so this should fail */
127     rv = apr_file_read(filetest, &str, &one);
128     CuAssertIntEquals(tc, 1, APR_STATUS_IS_EBADF(rv));
129 }
130
131 static void test_file_remove(CuTest *tc)
132 {
133     apr_status_t rv;
134     apr_file_t *filetest = NULL;
135
136     rv = apr_file_remove(FILENAME, p);
137     CuAssertIntEquals(tc, APR_SUCCESS, rv);
138
139     rv = apr_file_open(&filetest, FILENAME, APR_READ, 
140                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
141     CuAssertIntEquals(tc, 1, APR_STATUS_IS_ENOENT(rv));
142 }
143
144 static void test_open_write(CuTest *tc)
145 {
146     apr_status_t rv;
147     apr_file_t *filetest = NULL;
148
149     filetest = NULL;
150     rv = apr_file_open(&filetest, FILENAME, 
151                        APR_WRITE, 
152                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
153     CuAssertIntEquals(tc, 1, APR_STATUS_IS_ENOENT(rv));
154     CuAssertPtrEquals(tc, NULL, filetest);
155 }
156
157 static void test_open_writecreate(CuTest *tc)
158 {
159     apr_status_t rv;
160     apr_file_t *filetest = NULL;
161
162     filetest = NULL;
163     rv = apr_file_open(&filetest, FILENAME, 
164                        APR_WRITE | APR_CREATE, 
165                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
166     CuAssertIntEquals(tc, APR_SUCCESS, rv);
167
168     apr_file_close(filetest);
169 }
170
171 static void test_write(CuTest *tc)
172 {
173     apr_status_t rv;
174     apr_size_t bytes = strlen(TESTSTR);
175     apr_file_t *filetest = NULL;
176
177     rv = apr_file_open(&filetest, FILENAME, 
178                        APR_WRITE | APR_CREATE, 
179                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
180     CuAssertIntEquals(tc, APR_SUCCESS, rv);
181
182     rv = apr_file_write(filetest, TESTSTR, &bytes);
183     CuAssertIntEquals(tc, APR_SUCCESS, rv);
184
185     apr_file_close(filetest);
186 }
187
188 static void test_open_readwrite(CuTest *tc)
189 {
190     apr_status_t rv;
191     apr_file_t *filetest = NULL;
192
193     filetest = NULL;
194     rv = apr_file_open(&filetest, FILENAME, 
195                        APR_READ | APR_WRITE, 
196                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
197     CuAssertIntEquals(tc, APR_SUCCESS, rv);
198     CuAssertPtrNotNull(tc, filetest);
199
200     apr_file_close(filetest);
201 }
202
203 static void test_seek(CuTest *tc)
204 {
205     apr_status_t rv;
206     apr_off_t offset = 5;
207     apr_size_t nbytes = 256;
208     char *str = apr_pcalloc(p, nbytes + 1);
209     apr_file_t *filetest = NULL;
210
211     rv = apr_file_open(&filetest, FILENAME, 
212                        APR_READ, 
213                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
214     apr_assert_success(tc, "Open test file " FILENAME, rv);
215
216     rv = apr_file_read(filetest, str, &nbytes);
217     CuAssertIntEquals(tc, APR_SUCCESS, rv);
218     CuAssertIntEquals(tc, strlen(TESTSTR), nbytes);
219     CuAssertStrEquals(tc, TESTSTR, str);
220
221     memset(str, 0, nbytes + 1);
222
223     rv = apr_file_seek(filetest, SEEK_SET, &offset);
224     CuAssertIntEquals(tc, APR_SUCCESS, rv);
225     
226     rv = apr_file_read(filetest, str, &nbytes);
227     CuAssertIntEquals(tc, APR_SUCCESS, rv);
228     CuAssertIntEquals(tc, strlen(TESTSTR) - 5, nbytes);
229     CuAssertStrEquals(tc, TESTSTR + 5, str);
230
231     apr_file_close(filetest);
232
233     /* Test for regression of sign error bug with SEEK_END and
234        buffered files. */
235     rv = apr_file_open(&filetest, FILENAME,
236                        APR_READ | APR_BUFFERED,
237                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
238     apr_assert_success(tc, "Open test file " FILENAME, rv);
239
240     offset = -5;
241     rv = apr_file_seek(filetest, SEEK_END, &offset);
242     CuAssertIntEquals(tc, APR_SUCCESS, rv);
243     CuAssertIntEquals(tc, strlen(TESTSTR) - 5, offset);
244
245     memset(str, 0, nbytes + 1);
246     nbytes = 256;
247     rv = apr_file_read(filetest, str, &nbytes);
248     CuAssertIntEquals(tc, APR_SUCCESS, rv);
249     CuAssertIntEquals(tc, 5, nbytes);
250     CuAssertStrEquals(tc, TESTSTR + strlen(TESTSTR) - 5, str);
251
252     apr_file_close(filetest);
253 }                
254
255 static void test_userdata_set(CuTest *tc)
256 {
257     apr_status_t rv;
258     apr_file_t *filetest = NULL;
259
260     rv = apr_file_open(&filetest, FILENAME, 
261                        APR_WRITE, 
262                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
263     CuAssertIntEquals(tc, APR_SUCCESS, rv);
264
265     rv = apr_file_data_set(filetest, "This is a test",
266                            "test", apr_pool_cleanup_null);
267     CuAssertIntEquals(tc, APR_SUCCESS, rv);
268     apr_file_close(filetest);
269 }
270
271 static void test_userdata_get(CuTest *tc)
272 {
273     apr_status_t rv;
274     char *teststr;
275     apr_file_t *filetest = NULL;
276
277     rv = apr_file_open(&filetest, FILENAME, 
278                        APR_WRITE, 
279                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
280     CuAssertIntEquals(tc, APR_SUCCESS, rv);
281
282     rv = apr_file_data_set(filetest, "This is a test",
283                            "test", apr_pool_cleanup_null);
284     CuAssertIntEquals(tc, APR_SUCCESS, rv);
285
286     rv = apr_file_data_get((void **)&teststr, "test", filetest);
287     CuAssertIntEquals(tc, APR_SUCCESS, rv);
288     CuAssertStrEquals(tc, "This is a test", teststr);
289
290     apr_file_close(filetest);
291 }
292
293 static void test_userdata_getnokey(CuTest *tc)
294 {
295     apr_status_t rv;
296     char *teststr;
297     apr_file_t *filetest = NULL;
298
299     rv = apr_file_open(&filetest, FILENAME, 
300                        APR_WRITE, 
301                        APR_UREAD | APR_UWRITE | APR_GREAD, p);
302     CuAssertIntEquals(tc, APR_SUCCESS, rv);
303
304     rv = apr_file_data_get((void **)&teststr, "nokey", filetest);
305     CuAssertIntEquals(tc, APR_SUCCESS, rv);
306     CuAssertPtrEquals(tc, NULL, teststr);
307     apr_file_close(filetest);
308 }
309
310 static void test_getc(CuTest *tc)
311 {
312     apr_file_t *f = NULL;
313     apr_status_t rv;
314     char ch;
315
316     rv = apr_file_open(&f, FILENAME, APR_READ, 0, p);
317     CuAssertIntEquals(tc, APR_SUCCESS, rv);
318
319     apr_file_getc(&ch, f);
320     CuAssertIntEquals(tc, APR_SUCCESS, rv);
321     CuAssertIntEquals(tc, (int)TESTSTR[0], (int)ch);
322     apr_file_close(f);
323 }
324
325 static void test_ungetc(CuTest *tc)
326 {
327     apr_file_t *f = NULL;
328     apr_status_t rv;
329     char ch;
330
331     rv = apr_file_open(&f, FILENAME, APR_READ, 0, p);
332     CuAssertIntEquals(tc, APR_SUCCESS, rv);
333
334     apr_file_getc(&ch, f);
335     CuAssertIntEquals(tc, APR_SUCCESS, rv);
336     CuAssertIntEquals(tc, (int)TESTSTR[0], (int)ch);
337
338     apr_file_ungetc('X', f);
339     CuAssertIntEquals(tc, APR_SUCCESS, rv);
340
341     apr_file_getc(&ch, f);
342     CuAssertIntEquals(tc, APR_SUCCESS, rv);
343     CuAssertIntEquals(tc, 'X', (int)ch);
344
345     apr_file_close(f);
346 }
347
348 static void test_gets(CuTest *tc)
349 {
350     apr_file_t *f = NULL;
351     apr_status_t rv;
352     char *str = apr_palloc(p, 256);
353
354     rv = apr_file_open(&f, FILENAME, APR_READ, 0, p);
355     CuAssertIntEquals(tc, APR_SUCCESS, rv);
356
357     rv = apr_file_gets(str, 256, f);
358     /* Only one line in the test file, so APR will encounter EOF on the first
359      * call to gets, but we should get APR_SUCCESS on this call and
360      * APR_EOF on the next.
361      */
362     CuAssertIntEquals(tc, APR_SUCCESS, rv);
363     CuAssertStrEquals(tc, TESTSTR, str);
364     rv = apr_file_gets(str, 256, f);
365     CuAssertIntEquals(tc, APR_EOF, rv);
366     CuAssertStrEquals(tc, "", str);
367     apr_file_close(f);
368 }
369
370 static void test_bigread(CuTest *tc)
371 {
372     apr_file_t *f = NULL;
373     apr_status_t rv;
374     char buf[APR_BUFFERSIZE * 2];
375     apr_size_t nbytes;
376
377     /* Create a test file with known content.
378      */
379     rv = apr_file_open(&f, "data/created_file", 
380                        APR_CREATE | APR_WRITE | APR_TRUNCATE, 
381                        APR_UREAD | APR_UWRITE, p);
382     CuAssertIntEquals(tc, APR_SUCCESS, rv);
383
384     nbytes = APR_BUFFERSIZE;
385     memset(buf, 0xFE, nbytes);
386
387     rv = apr_file_write(f, buf, &nbytes);
388     CuAssertIntEquals(tc, APR_SUCCESS, rv);
389     CuAssertIntEquals(tc, APR_BUFFERSIZE, nbytes);
390
391     rv = apr_file_close(f);
392     CuAssertIntEquals(tc, APR_SUCCESS, rv);
393
394     f = NULL;
395     rv = apr_file_open(&f, "data/created_file", APR_READ, 0, p);
396     CuAssertIntEquals(tc, APR_SUCCESS, rv);
397
398     nbytes = sizeof buf;
399     rv = apr_file_read(f, buf, &nbytes);
400     CuAssertIntEquals(tc, APR_SUCCESS, rv);
401     CuAssertIntEquals(tc, APR_BUFFERSIZE, nbytes);
402
403     rv = apr_file_close(f);
404     CuAssertIntEquals(tc, APR_SUCCESS, rv);
405
406     rv = apr_file_remove("data/created_file", p);
407     CuAssertIntEquals(tc, APR_SUCCESS, rv);
408 }
409
410 /* Test that the contents of file FNAME are equal to data EXPECT of
411  * length EXPECTLEN. */
412 static void file_contents_equal(CuTest *tc,
413                                 const char *fname,
414                                 const void *expect,
415                                 apr_size_t expectlen)
416 {
417     void *actual = apr_palloc(p, expectlen);
418     apr_file_t *f;
419     apr_status_t rv;
420     int rc;
421     
422     rv = apr_file_open(&f, fname, APR_READ|APR_BUFFERED, 0, p);
423     CuAssertIntEquals(tc, APR_SUCCESS, rv);
424
425     rv = apr_file_read_full(f, actual, expectlen, NULL);
426     CuAssertIntEquals(tc, APR_SUCCESS, rv);
427
428     rc = memcmp(expect, actual, expectlen);
429     CuAssertIntEquals(tc, 0, rc);
430
431     rv = apr_file_close(f);
432     CuAssertIntEquals(tc, APR_SUCCESS, rv);
433 }
434
435 #define LINE1 "this is a line of text\n"
436 #define LINE2 "this is a second line of text\n"
437
438 static void test_writev_buffered(CuTest *tc)
439 {
440     apr_status_t rv;
441     apr_file_t *f;
442     apr_size_t nbytes;
443     struct iovec vec[2];
444     const char *fname = "data/testwritev_buffered.dat";
445
446     rv = apr_file_open(&f, fname,
447                        APR_WRITE | APR_CREATE | APR_TRUNCATE |
448                        APR_BUFFERED, APR_OS_DEFAULT, p);
449     CuAssertIntEquals(tc, APR_SUCCESS, rv);
450
451     nbytes = strlen(TESTSTR);
452     rv = apr_file_write(f, TESTSTR, &nbytes);
453     CuAssertIntEquals(tc, APR_SUCCESS, rv);
454
455     vec[0].iov_base = LINE1;
456     vec[0].iov_len = strlen(LINE1);
457     vec[1].iov_base = LINE2;
458     vec[1].iov_len = strlen(LINE2);
459
460     rv = apr_file_writev(f, vec, 2, &nbytes);
461     CuAssertIntEquals(tc, APR_SUCCESS, rv);
462
463     rv = apr_file_close(f);
464     CuAssertIntEquals(tc, APR_SUCCESS, rv);
465
466     file_contents_equal(tc, fname, TESTSTR LINE1 LINE2,
467                         strlen(TESTSTR) + strlen(LINE1) + strlen(LINE2));
468 }
469
470 static void test_writev_buffered_seek(CuTest *tc)
471 {
472     apr_file_t *f;
473     apr_status_t rv;
474     apr_off_t off = 0;
475     struct iovec vec[3];
476     apr_size_t nbytes = strlen(TESTSTR);
477     char *str = apr_pcalloc(p, nbytes+1);
478     const char *fname = "data/testwritev_buffered.dat";
479
480     rv = apr_file_open(&f, fname,
481                        APR_WRITE | APR_READ | APR_BUFFERED,
482                        APR_OS_DEFAULT, p);
483
484     rv = apr_file_read(f, str, &nbytes);
485     CuAssertIntEquals(tc, APR_SUCCESS, rv);
486     CuAssertStrEquals(tc, TESTSTR, str);
487
488     rv = apr_file_seek(f, APR_SET, &off);
489     CuAssertIntEquals(tc, APR_SUCCESS, rv);
490
491     vec[0].iov_base = LINE1;
492     vec[0].iov_len = strlen(LINE1);
493     vec[1].iov_base = LINE2;
494     vec[1].iov_len = strlen(LINE2);
495     vec[2].iov_base = TESTSTR;
496     vec[2].iov_len = strlen(TESTSTR);
497
498     rv = apr_file_writev(f, vec, 3, &nbytes);
499     CuAssertIntEquals(tc, APR_SUCCESS, rv);
500
501     rv = apr_file_close(f);
502     CuAssertIntEquals(tc, APR_SUCCESS, rv);
503
504     file_contents_equal(tc, fname, LINE1 LINE2 TESTSTR,
505                         strlen(LINE1) + strlen(LINE2) + strlen(TESTSTR));
506
507     rv = apr_file_remove(fname, p);
508     CuAssertIntEquals(tc, APR_SUCCESS, rv);
509 }
510
511 /* This is a horrible name for this function.  We are testing APR, not how
512  * Apache uses APR.  And, this function tests _way_ too much stuff.
513  */
514 static void test_mod_neg(CuTest *tc)
515 {
516     apr_status_t rv;
517     apr_file_t *f;
518     const char *s;
519     int i;
520     apr_size_t nbytes;
521     char buf[8192];
522     apr_off_t cur;
523     const char *fname = "data/modneg.dat";
524
525     rv = apr_file_open(&f, fname, 
526                        APR_CREATE | APR_WRITE, APR_UREAD | APR_UWRITE, p);
527     CuAssertIntEquals(tc, APR_SUCCESS, rv);
528
529     s = "body56789\n";
530     nbytes = strlen(s);
531     rv = apr_file_write(f, s, &nbytes);
532     CuAssertIntEquals(tc, APR_SUCCESS, rv);
533     CuAssertIntEquals(tc, strlen(s), nbytes);
534     
535     for (i = 0; i < 7980; i++) {
536         s = "0";
537         nbytes = strlen(s);
538         rv = apr_file_write(f, s, &nbytes);
539         CuAssertIntEquals(tc, APR_SUCCESS, rv);
540         CuAssertIntEquals(tc, strlen(s), nbytes);
541     }
542     
543     s = "end456789\n";
544     nbytes = strlen(s);
545     rv = apr_file_write(f, s, &nbytes);
546     CuAssertIntEquals(tc, APR_SUCCESS, rv);
547     CuAssertIntEquals(tc, strlen(s), nbytes);
548
549     for (i = 0; i < 10000; i++) {
550         s = "1";
551         nbytes = strlen(s);
552         rv = apr_file_write(f, s, &nbytes);
553         CuAssertIntEquals(tc, APR_SUCCESS, rv);
554         CuAssertIntEquals(tc, strlen(s), nbytes);
555     }
556     
557     rv = apr_file_close(f);
558     CuAssertIntEquals(tc, APR_SUCCESS, rv);
559
560     rv = apr_file_open(&f, fname, APR_READ, 0, p);
561     CuAssertIntEquals(tc, APR_SUCCESS, rv);
562
563     rv = apr_file_gets(buf, 11, f);
564     CuAssertIntEquals(tc, APR_SUCCESS, rv);
565     CuAssertStrEquals(tc, "body56789\n", buf);
566
567     cur = 0;
568     rv = apr_file_seek(f, APR_CUR, &cur);
569     CuAssertIntEquals(tc, APR_SUCCESS, rv);
570     CuAssert(tc, "File Pointer Mismatch, expected 10", cur == 10);
571
572     nbytes = sizeof(buf);
573     rv = apr_file_read(f, buf, &nbytes);
574     CuAssertIntEquals(tc, APR_SUCCESS, rv);
575     CuAssertIntEquals(tc, nbytes, sizeof(buf));
576
577     cur = -((apr_off_t)nbytes - 7980);
578     rv = apr_file_seek(f, APR_CUR, &cur);
579     CuAssertIntEquals(tc, APR_SUCCESS, rv);
580     CuAssert(tc, "File Pointer Mismatch, expected 7990", cur == 7990);
581
582     rv = apr_file_gets(buf, 11, f);
583     CuAssertIntEquals(tc, APR_SUCCESS, rv);
584     CuAssertStrEquals(tc, "end456789\n", buf);
585
586     rv = apr_file_close(f);
587     CuAssertIntEquals(tc, APR_SUCCESS, rv);
588
589     rv = apr_file_remove(fname, p);
590     CuAssertIntEquals(tc, APR_SUCCESS, rv);
591 }
592
593 static void test_truncate(CuTest *tc)
594 {
595     apr_status_t rv;
596     apr_file_t *f;
597     const char *fname = "data/testtruncate.dat";
598     const char *s;
599     apr_size_t nbytes;
600     apr_finfo_t finfo;
601
602     apr_file_remove(fname, p);
603
604     rv = apr_file_open(&f, fname,
605                        APR_CREATE | APR_WRITE, APR_UREAD | APR_UWRITE, p);
606     CuAssertIntEquals(tc, APR_SUCCESS, rv);
607     
608     s = "some data";
609     nbytes = strlen(s);
610     rv = apr_file_write(f, s, &nbytes);
611     CuAssertIntEquals(tc, APR_SUCCESS, rv);
612     CuAssertIntEquals(tc, strlen(s), nbytes);
613
614     rv = apr_file_close(f);
615     CuAssertIntEquals(tc, APR_SUCCESS, rv);
616
617     rv = apr_file_open(&f, fname,
618                        APR_TRUNCATE | APR_WRITE, APR_UREAD | APR_UWRITE, p);
619     CuAssertIntEquals(tc, APR_SUCCESS, rv);
620
621     rv = apr_file_close(f);
622     CuAssertIntEquals(tc, APR_SUCCESS, rv);
623
624     rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, p);
625     CuAssertIntEquals(tc, APR_SUCCESS, rv);
626     CuAssert(tc, "File size mismatch, expected 0 (empty)", finfo.size == 0);
627
628     rv = apr_file_remove(fname, p);
629     CuAssertIntEquals(tc, APR_SUCCESS, rv);
630 }
631
632 static void test_fail_write_flush(CuTest *tc)
633 {
634     apr_file_t *f;
635     const char *fname = "data/testflush.dat";
636     apr_status_t rv;
637     char buf[APR_BUFFERSIZE];
638     int n;
639
640     apr_file_remove(fname, p);
641
642     apr_assert_success(tc, "open test file",
643                        apr_file_open(&f, fname,
644                                      APR_CREATE|APR_READ|APR_BUFFERED,
645                                      APR_UREAD|APR_UWRITE, p));
646
647     memset(buf, 'A', sizeof buf);
648
649     /* Try three writes.  One of these should fail when it exceeds the
650      * internal buffer and actually tries to write to the file, which
651      * was opened read-only and hence should be unwritable. */
652     for (n = 0, rv = APR_SUCCESS; n < 4 && rv == APR_SUCCESS; n++) {
653         apr_size_t bytes = sizeof buf;
654         rv = apr_file_write(f, buf, &bytes);
655     }
656
657     CuAssert(tc, "failed to write to read-only buffered fd",
658              rv != APR_SUCCESS);
659
660     apr_file_close(f);
661     apr_file_remove(fname, p);
662 }
663
664 static void test_fail_read_flush(CuTest *tc)
665 {
666     apr_file_t *f;
667     const char *fname = "data/testflush.dat";
668     apr_status_t rv;
669     char buf[2];
670
671     apr_file_remove(fname, p);
672
673     apr_assert_success(tc, "open test file",
674                        apr_file_open(&f, fname,
675                                      APR_CREATE|APR_READ|APR_BUFFERED,
676                                      APR_UREAD|APR_UWRITE, p));
677
678     /* this write should be buffered. */
679     apr_assert_success(tc, "buffered write should succeed",
680                        apr_file_puts("hello", f));
681
682     /* Now, trying a read should fail since the write must be flushed,
683      * and should fail with something other than EOF since the file is
684      * opened read-only. */
685     rv = apr_file_read_full(f, buf, 2, NULL);
686
687     CuAssert(tc, "read should flush buffered write and fail",
688              rv != APR_SUCCESS && rv != APR_EOF);
689
690     /* Likewise for gets */
691     rv = apr_file_gets(buf, 2, f);
692
693     CuAssert(tc, "gets should flush buffered write and fail",
694              rv != APR_SUCCESS && rv != APR_EOF);
695
696     apr_file_close(f);
697     apr_file_remove(fname, p);
698 }
699
700 static void test_xthread(CuTest *tc)
701 {
702     apr_file_t *f;
703     const char *fname = "data/testxthread.dat";
704     apr_status_t rv;
705     apr_int32_t flags = APR_CREATE|APR_READ|APR_WRITE|APR_APPEND|APR_XTHREAD;
706     char buf[128] = { 0 };
707
708     /* Test for bug 38438, opening file with append + xthread and seeking to 
709        the end of the file resulted in writes going to the beginning not the
710        end. */
711
712     apr_file_remove(fname, p);
713
714     rv = apr_file_open(&f, fname, flags, APR_UREAD|APR_UWRITE, p);
715     CuAssert(tc, "open test file", rv == APR_SUCCESS);
716
717     rv = apr_file_puts("hello", f);
718     CuAssert(tc, "write should succeed", rv == APR_SUCCESS);
719
720     apr_file_close(f);
721     
722     rv = apr_file_open(&f, fname, flags, APR_UREAD|APR_UWRITE, p);
723     CuAssert(tc, "open test file", rv == APR_SUCCESS);
724
725     /* Seek to the end. */
726     {
727         apr_off_t offset = 0;
728
729         rv = apr_file_seek(f, APR_END, &offset);
730     }
731
732     rv = apr_file_puts("world", f);
733     CuAssert(tc, "more writes should succeed", rv == APR_SUCCESS);
734
735     /* Back to the beginning. */
736     {
737         apr_off_t offset = 0;
738         
739         rv = apr_file_seek(f, APR_SET, &offset);
740     }
741     
742     apr_file_read_full(f, buf, sizeof(buf), NULL);
743
744     CuAssertStrEquals(tc, "helloworld", buf);
745
746     apr_file_close(f);
747 }
748
749 CuSuite *testfile(void)
750 {
751     CuSuite *suite = CuSuiteNew("File I/O");
752
753     SUITE_ADD_TEST(suite, test_open_noreadwrite);
754     SUITE_ADD_TEST(suite, test_open_excl);
755     SUITE_ADD_TEST(suite, test_open_read);
756     SUITE_ADD_TEST(suite, test_open_readwrite);
757     SUITE_ADD_TEST(suite, test_read); 
758     SUITE_ADD_TEST(suite, test_seek);
759     SUITE_ADD_TEST(suite, test_filename);
760     SUITE_ADD_TEST(suite, test_fileclose);
761     SUITE_ADD_TEST(suite, test_file_remove);
762     SUITE_ADD_TEST(suite, test_open_write);
763     SUITE_ADD_TEST(suite, test_open_writecreate);
764     SUITE_ADD_TEST(suite, test_write);
765     SUITE_ADD_TEST(suite, test_userdata_set);
766     SUITE_ADD_TEST(suite, test_userdata_get);
767     SUITE_ADD_TEST(suite, test_userdata_getnokey);
768     SUITE_ADD_TEST(suite, test_getc);
769     SUITE_ADD_TEST(suite, test_ungetc);
770     SUITE_ADD_TEST(suite, test_gets);
771     SUITE_ADD_TEST(suite, test_bigread);
772     SUITE_ADD_TEST(suite, test_writev_buffered);
773     SUITE_ADD_TEST(suite, test_writev_buffered_seek);
774     SUITE_ADD_TEST(suite, test_mod_neg);
775     SUITE_ADD_TEST(suite, test_truncate);
776     SUITE_ADD_TEST(suite, test_fail_write_flush);
777     SUITE_ADD_TEST(suite, test_fail_read_flush);
778     SUITE_ADD_TEST(suite, test_xthread);
779
780     return suite;
781 }
782