Flush the standard error stream before aborting.
[gnulib.git] / tests / test-fwriting.c
1 /* Test of fwriting() function.
2    Copyright (C) 2007-2008 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
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 General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
18
19 #include <config.h>
20
21 #include "fwriting.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #define ASSERT(expr) \
27   do                                                                         \
28     {                                                                        \
29       if (!(expr))                                                           \
30         {                                                                    \
31           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
32           fflush (stderr);                                                   \
33           abort ();                                                          \
34         }                                                                    \
35     }                                                                        \
36   while (0)
37
38 #define TESTFILE "t-fwriting.tmp"
39
40 int
41 main ()
42 {
43   FILE *fp;
44
45   /* Create a file with some contents.  Write-only file is always writing.  */
46   fp = fopen (TESTFILE, "w");
47   if (fp == NULL)
48     goto skip;
49   ASSERT (fwriting (fp));
50   if (fwrite ("foobarsh", 1, 8, fp) < 8)
51     goto skip;
52   ASSERT (fwriting (fp));
53   if (fclose (fp))
54     goto skip;
55
56   /* Open it in read-only mode.  Read-only file is never writing.  */
57   fp = fopen (TESTFILE, "r");
58   if (fp == NULL)
59     goto skip;
60   ASSERT (!fwriting (fp));
61   if (fgetc (fp) != 'f')
62     goto skip;
63   ASSERT (!fwriting (fp));
64   if (fseek (fp, 2, SEEK_CUR))
65     goto skip;
66   ASSERT (!fwriting (fp));
67   if (fgetc (fp) != 'b')
68     goto skip;
69   ASSERT (!fwriting (fp));
70   fflush (fp);
71   ASSERT (!fwriting (fp));
72   if (fgetc (fp) != 'a')
73     goto skip;
74   ASSERT (!fwriting (fp));
75   if (fseek (fp, 0, SEEK_END))
76     goto skip;
77   ASSERT (!fwriting (fp));
78   if (fclose (fp))
79     goto skip;
80
81   /* Open it in read-write mode.  POSIX requires a reposition (fseek,
82      fsetpos, rewind) or fflush when transitioning from write to read,
83      fwriting is only deterministic after input or output, but this
84      test case should be portable even on open, after reposition, and
85      after fflush.  */
86   /* First a scenario with only fgetc, fseek, fputc.  */
87   fp = fopen (TESTFILE, "r+");
88   if (fp == NULL)
89     goto skip;
90   ASSERT (!fwriting (fp));
91   if (fgetc (fp) != 'f')
92     goto skip;
93   ASSERT (!fwriting (fp));
94   if (fseek (fp, 2, SEEK_CUR))
95     goto skip;
96   ASSERT (!fwriting (fp));
97   if (fgetc (fp) != 'b')
98     goto skip;
99   ASSERT (!fwriting (fp));
100   /* This fseek call is necessary when switching from reading to writing.
101      See the description of fopen(), ISO C 99 7.19.5.3.(6).  */
102   if (fseek (fp, 0, SEEK_CUR) != 0)
103     goto skip;
104   ASSERT (!fwriting (fp));
105   if (fputc ('x', fp) != 'x')
106     goto skip;
107   ASSERT (fwriting (fp));
108   if (fseek (fp, 0, SEEK_END))
109     goto skip;
110   /* freading (fp) is undefined here, because on some implementations (e.g.
111      glibc) fseek causes a buffer to be read.
112      fwriting (fp) is undefined as well.  */
113   if (fclose (fp))
114     goto skip;
115
116   /* Open it in read-write mode.  POSIX requires a reposition (fseek,
117      fsetpos, rewind) or fflush when transitioning from write to read,
118      fwriting is only deterministic after input or output, but this
119      test case should be portable even on open, after reposition, and
120      after fflush.  */
121   /* Here a scenario that includes fflush.  */
122   fp = fopen (TESTFILE, "r+");
123   if (fp == NULL)
124     goto skip;
125   ASSERT (!fwriting (fp));
126   if (fgetc (fp) != 'f')
127     goto skip;
128   ASSERT (!fwriting (fp));
129   if (fseek (fp, 2, SEEK_CUR))
130     goto skip;
131   ASSERT (!fwriting (fp));
132   if (fgetc (fp) != 'b')
133     goto skip;
134   ASSERT (!fwriting (fp));
135   fflush (fp);
136   ASSERT (!fwriting (fp));
137   if (fgetc (fp) != 'x')
138     goto skip;
139   ASSERT (!fwriting (fp));
140   /* This fseek call is necessary when switching from reading to writing.
141      See the description of fopen(), ISO C 99 7.19.5.3.(6).  */
142   if (fseek (fp, 0, SEEK_CUR) != 0)
143     goto skip;
144   ASSERT (!fwriting (fp));
145   if (fputc ('z', fp) != 'z')
146     goto skip;
147   ASSERT (fwriting (fp));
148   if (fseek (fp, 0, SEEK_END))
149     goto skip;
150   /* freading (fp) is undefined here, because on some implementations (e.g.
151      glibc) fseek causes a buffer to be read.
152      fwriting (fp) is undefined as well.  */
153   if (fclose (fp))
154     goto skip;
155
156   /* Open it in append mode.  */
157   fp = fopen (TESTFILE, "a");
158   if (fp == NULL)
159     goto skip;
160   ASSERT (fwriting (fp));
161   if (fwrite ("bla", 1, 3, fp) < 3)
162     goto skip;
163   ASSERT (fwriting (fp));
164   if (fclose (fp))
165     goto skip;
166
167   return 0;
168
169  skip:
170   fprintf (stderr, "Skipping test: file operations failed.\n");
171   return 77;
172 }