Flush the standard error stream before aborting.
[gnulib.git] / tests / test-stat-time.c
1 /* Test of <stat-time.h>.
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 James Youngman <jay@gnu.org>, 2007.  */
18
19 #include <config.h>
20
21 #include "stat-time.h"
22
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 #define ASSERT(expr) \
31   do                                                                         \
32     {                                                                        \
33       if (!(expr))                                                           \
34         {                                                                    \
35           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
36           fflush (stderr);                                                   \
37           abort ();                                                          \
38         }                                                                    \
39     }                                                                        \
40   while (0)
41
42 enum { NFILES = 4 };
43
44 static void
45 cleanup (int sig)
46 {
47   /* Remove temporary files.  */
48   unlink ("t-stt-stamp1");
49   unlink ("t-stt-testfile");
50   unlink ("t-stt-stamp2");
51   unlink ("t-stt-renamed");
52   unlink ("t-stt-stamp3");
53
54   if (sig != 0)
55     _exit (1);
56 }
57
58 static int
59 open_file (const char *filename, int flags)
60 {
61   int fd = open (filename, flags | O_WRONLY, 0500);
62   if (fd >= 0)
63     {
64       close (fd);
65       return 1;
66     }
67   else
68     {
69       return 0;
70     }
71 }
72
73 static void
74 create_file (const char *filename)
75 {
76   ASSERT (open_file (filename, O_CREAT | O_EXCL));
77 }
78
79 static void
80 do_stat (const char *filename, struct stat *p)
81 {
82   ASSERT (stat (filename, p) == 0);
83 }
84
85 static void
86 prepare_test (struct stat *statinfo, struct timespec *modtimes)
87 {
88   int i;
89
90   create_file ("t-stt-stamp1");
91   sleep (2);
92   create_file ("t-stt-testfile");
93   sleep (2);
94   create_file ("t-stt-stamp2");
95   sleep (2);
96   ASSERT (chmod ("t-stt-testfile", 0400) == 0);
97   sleep (2);
98   create_file ("t-stt-stamp3");
99
100   do_stat ("t-stt-stamp1",  &statinfo[0]);
101   do_stat ("t-stt-testfile", &statinfo[1]);
102   do_stat ("t-stt-stamp2",  &statinfo[2]);
103   do_stat ("t-stt-stamp3",  &statinfo[3]);
104
105   /* Now use our access functions. */
106   for (i = 0; i < NFILES; ++i)
107     {
108       modtimes[i] = get_stat_mtime (&statinfo[i]);
109     }
110 }
111
112 static void
113 test_mtime (const struct stat *statinfo, struct timespec *modtimes)
114 {
115   int i;
116
117   /* Use the struct stat fields directly. */
118   ASSERT (statinfo[0].st_mtime < statinfo[2].st_mtime); /* mtime(stamp1) < mtime(stamp2) */
119   ASSERT (statinfo[2].st_mtime < statinfo[3].st_mtime); /* mtime(stamp2) < mtime(stamp3) */
120   ASSERT (statinfo[2].st_mtime < statinfo[1].st_ctime); /* mtime(stamp2) < ctime(renamed) */
121
122   /* Now check the result of the access functions. */
123   ASSERT (modtimes[0].tv_sec < modtimes[2].tv_sec); /* mtime(stamp1) < mtime(stamp2) */
124   ASSERT (modtimes[2].tv_sec < modtimes[3].tv_sec); /* mtime(stamp2) < mtime(stamp3) */
125
126   /* verify equivalence */
127   for (i = 0; i < NFILES; ++i)
128     {
129       struct timespec ts;
130       ts = get_stat_mtime (&statinfo[i]);
131       ASSERT (ts.tv_sec == statinfo[i].st_mtime);
132     }
133
134   ASSERT (statinfo[2].st_mtime < statinfo[1].st_ctime); /* mtime(stamp2) < ctime(renamed) */
135 }
136
137 static void
138 test_birthtime (const struct stat *statinfo,
139                 const struct timespec *modtimes,
140                 struct timespec *birthtimes)
141 {
142   int i;
143
144   /* Collect the birth times.. */
145   for (i = 0; i < NFILES; ++i)
146     {
147       birthtimes[i] = get_stat_birthtime (&statinfo[i]);
148       if (birthtimes[i].tv_nsec < 0)
149         return;
150     }
151
152   ASSERT (modtimes[0].tv_sec < birthtimes[1].tv_sec); /* mtime(stamp1) < birthtime(renamed) */
153   ASSERT (birthtimes[1].tv_sec < modtimes[2].tv_sec); /* birthtime(renamed) < mtime(stamp2) */
154 }
155
156 int
157 main ()
158 {
159   struct stat statinfo[NFILES];
160   struct timespec modtimes[NFILES];
161   struct timespec birthtimes[NFILES];
162
163 #ifdef SIGHUP
164   signal (SIGHUP, cleanup);
165 #endif
166 #ifdef SIGINT
167   signal (SIGINT, cleanup);
168 #endif
169 #ifdef SIGQUIT
170   signal (SIGQUIT, cleanup);
171 #endif
172 #ifdef SIGTERM
173   signal (SIGTERM, cleanup);
174 #endif
175
176   cleanup (0);
177   prepare_test (statinfo, modtimes);
178   test_mtime (statinfo, modtimes);
179   test_birthtime (statinfo, modtimes, birthtimes);
180
181   cleanup (0);
182   return 0;
183 }