utimens: add test
[gnulib.git] / tests / test-futimens.h
1 /* Test of file timestamp modification functions.
2    Copyright (C) 2009 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 2 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 /* This file assumes that BASE and ASSERT are already defined.  */
18
19 #ifndef GL_TEST_UTIMENS
20 # define GL_TEST_UTIMENS
21
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "stat-time.h"
28 #include "timespec.h"
29 #include "utimecmp.h"
30
31 enum {
32   BILLION = 1000 * 1000 * 1000,
33
34   Y2K = 946684800, /* Jan 1, 2000, in seconds since epoch.  */
35
36   /* Bogus positive and negative tv_nsec values closest to valid
37      range, but without colliding with UTIME_NOW or UTIME_OMIT.  */
38   UTIME_BOGUS_POS = BILLION + ((UTIME_NOW == BILLION || UTIME_OMIT == BILLION)
39                                ? (1 + (UTIME_NOW == BILLION + 1)
40                                   + (UTIME_OMIT == BILLION + 1))
41                                : 0),
42   UTIME_BOGUS_NEG = -1 - ((UTIME_NOW == -1 || UTIME_OMIT == -1)
43                           ? (1 + (UTIME_NOW == -2) + (UTIME_OMIT == -2))
44                           : 0)
45 };
46
47 #endif /* GL_TEST_UTIMENS */
48
49 /* This function is designed to test both gl_futimens(a,NULL,b) and
50    futimens(a,b).  FUNC is the function to test.  If PRINT, warn
51    before skipping tests with status 77.  */
52 static int
53 test_futimens (int (*func) (int, struct timespec const *),
54                bool print)
55 {
56   int fd = creat (BASE "file", 0600);
57   int result;
58   struct stat st1;
59   struct stat st2;
60   ASSERT (0 <= fd);
61
62   /* Sanity check.  */
63   errno = 0;
64   result = func (fd, NULL);
65   if (result == -1 && errno == ENOSYS)
66     {
67       ASSERT (close (fd) == 0);
68       ASSERT (unlink (BASE "file") == 0);
69       if (print)
70         fputs ("skipping test: "
71                "setting fd time not supported on this file system\n",
72                stderr);
73       return 77;
74     }
75   ASSERT (!result);
76   ASSERT (fstat (fd, &st1) == 0);
77
78   /* Invalid arguments.  */
79   errno = 0;
80   ASSERT (func (AT_FDCWD, NULL) == -1);
81   ASSERT (errno == EBADF);
82   {
83     struct timespec ts[2] = { { Y2K, UTIME_BOGUS_POS }, { Y2K, 0 } };
84     errno = 0;
85     ASSERT (func (fd, ts) == -1);
86     ASSERT (errno == EINVAL);
87   }
88   {
89     struct timespec ts[2] = { { Y2K, 0 }, { Y2K, UTIME_BOGUS_NEG } };
90     errno = 0;
91     ASSERT (func (fd, ts) == -1);
92     ASSERT (errno == EINVAL);
93   }
94   ASSERT (fstat (fd, &st2) == 0);
95   ASSERT (st1.st_atime == st2.st_atime);
96   ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
97   ASSERT (utimecmp (BASE "file", &st1, &st2, 0) == 0);
98
99   /* Set both times.  */
100   {
101     struct timespec ts[2] = { { Y2K, BILLION / 2 - 1 }, { Y2K, BILLION - 1 } };
102     ASSERT (func (fd, ts) == 0);
103     ASSERT (fstat (fd, &st2) == 0);
104     ASSERT (st2.st_atime == Y2K);
105     ASSERT (0 <= get_stat_atime_ns (&st2));
106     ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
107     ASSERT (st2.st_mtime == Y2K);
108     ASSERT (0 <= get_stat_mtime_ns (&st2));
109     ASSERT (get_stat_mtime_ns (&st2) < BILLION);
110   }
111
112   /* Play with UTIME_OMIT, UTIME_NOW.  */
113   {
114     struct timespec ts[2] = { { BILLION, UTIME_OMIT }, { 0, UTIME_NOW } };
115     ASSERT (func (fd, ts) == 0);
116     ASSERT (fstat (fd, &st2) == 0);
117     ASSERT (st2.st_atime == Y2K);
118     ASSERT (0 <= get_stat_atime_ns (&st2));
119     ASSERT (get_stat_atime_ns (&st2) <= BILLION / 2);
120     ASSERT (utimecmp (BASE "file", &st1, &st2, 0) <= 0);
121   }
122
123   /* Cleanup.  */
124   ASSERT (close (fd) == 0);
125   ASSERT (unlink (BASE "file") == 0);
126   return 0;
127 }