maint: update copyright
[gnulib.git] / tests / test-utimens.h
index 08d3ac0..fd696a0 100644 (file)
@@ -1,9 +1,9 @@
 /* Test of file timestamp modification functions.
 /* Test of file timestamp modification functions.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009-2014 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-/* This file assumes that BASE and ASSERT are already defined.  */
+#include "test-utimens-common.h"
 
 
-#ifndef GL_TEST_UTIMENS
-# define GL_TEST_UTIMENS
-
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "stat-time.h"
-#include "timespec.h"
-#include "utimecmp.h"
-
-enum {
-  BILLION = 1000 * 1000 * 1000,
-
-  Y2K = 946684800, /* Jan 1, 2000, in seconds since epoch.  */
-
-  /* Bogus positive and negative tv_nsec values closest to valid
-     range, but without colliding with UTIME_NOW or UTIME_OMIT.  */
-  UTIME_BOGUS_POS = BILLION + ((UTIME_NOW == BILLION || UTIME_OMIT == BILLION)
-                               ? (1 + (UTIME_NOW == BILLION + 1)
-                                  + (UTIME_OMIT == BILLION + 1))
-                               : 0),
-  UTIME_BOGUS_NEG = -1 - ((UTIME_NOW == -1 || UTIME_OMIT == -1)
-                          ? (1 + (UTIME_NOW == -2) + (UTIME_OMIT == -2))
-                          : 0)
-};
-
-#endif /* GL_TEST_UTIMENS */
-
-/* This function is designed to test both utimens(a,b) and
-   utimensat(AT_FDCWD,a,b,0).  FUNC is the function to test.  */
+/* This file is designed to test both utimens(a,b) and
+   utimensat(AT_FDCWD,a,b,0).  FUNC is the function to test.  Assumes
+   that BASE and ASSERT are already defined.  If PRINT, warn before
+   skipping tests with status 77.  */
 static int
 static int
-test_utimens (int (*func) (char const *, struct timespec const *))
+test_utimens (int (*func) (char const *, struct timespec const *), bool print)
 {
   struct stat st1;
   struct stat st2;
 {
   struct stat st1;
   struct stat st2;
@@ -61,13 +33,16 @@ test_utimens (int (*func) (char const *, struct timespec const *))
      UTIMECMP_TRUNCATE_SOURCE to compensate, with st1 as the
      source.  */
   ASSERT (stat (BASE "file", &st1) == 0);
      UTIMECMP_TRUNCATE_SOURCE to compensate, with st1 as the
      source.  */
   ASSERT (stat (BASE "file", &st1) == 0);
+  nap ();
   ASSERT (func (BASE "file", NULL) == 0);
   ASSERT (stat (BASE "file", &st2) == 0);
   ASSERT (0 <= utimecmp (BASE "file", &st2, &st1, UTIMECMP_TRUNCATE_SOURCE));
   ASSERT (func (BASE "file", NULL) == 0);
   ASSERT (stat (BASE "file", &st2) == 0);
   ASSERT (0 <= utimecmp (BASE "file", &st2, &st1, UTIMECMP_TRUNCATE_SOURCE));
+  if (check_ctime)
+    ASSERT (ctime_compare (&st1, &st2) < 0);
   {
     /* On some NFS systems, the 'now' timestamp of creat or a NULL
        timespec is determined by the server, but the 'now' timestamp
   {
     /* On some NFS systems, the 'now' timestamp of creat or a NULL
        timespec is determined by the server, but the 'now' timestamp
-       determined by gettime() (as is done when using UTIME_OMIT) is
+       determined by gettime() (as is done when using UTIME_NOW) is
        determined by the client; since the two machines are not
        necessarily on the same clock, this is another case where time
        can appear to go backwards.  The rest of this test cares about
        determined by the client; since the two machines are not
        necessarily on the same clock, this is another case where time
        can appear to go backwards.  The rest of this test cares about
@@ -77,6 +52,7 @@ test_utimens (int (*func) (char const *, struct timespec const *))
     ts[1] = ts[0];
     ASSERT (func (BASE "file", ts) == 0);
     ASSERT (stat (BASE "file", &st1) == 0);
     ts[1] = ts[0];
     ASSERT (func (BASE "file", ts) == 0);
     ASSERT (stat (BASE "file", &st1) == 0);
+    nap ();
   }
 
   /* Invalid arguments.  */
   }
 
   /* Invalid arguments.  */
@@ -84,6 +60,9 @@ test_utimens (int (*func) (char const *, struct timespec const *))
   ASSERT (func ("no_such", NULL) == -1);
   ASSERT (errno == ENOENT);
   errno = 0;
   ASSERT (func ("no_such", NULL) == -1);
   ASSERT (errno == ENOENT);
   errno = 0;
+  ASSERT (func ("no_such/", NULL) == -1);
+  ASSERT (errno == ENOENT || errno == ENOTDIR);
+  errno = 0;
   ASSERT (func ("", NULL) == -1);
   ASSERT (errno == ENOENT);
   {
   ASSERT (func ("", NULL) == -1);
   ASSERT (errno == ENOENT);
   {
@@ -98,6 +77,12 @@ test_utimens (int (*func) (char const *, struct timespec const *))
     ASSERT (func (BASE "file", ts) == -1);
     ASSERT (errno == EINVAL);
   }
     ASSERT (func (BASE "file", ts) == -1);
     ASSERT (errno == EINVAL);
   }
+  {
+    struct timespec ts[2] = { { Y2K, 0 }, { Y2K, 0 } };
+    errno = 0;
+    ASSERT (func (BASE "file/", ts) == -1);
+    ASSERT (errno == ENOTDIR || errno == EINVAL);
+  }
   ASSERT (stat (BASE "file", &st2) == 0);
   ASSERT (st1.st_atime == st2.st_atime);
   ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
   ASSERT (stat (BASE "file", &st2) == 0);
   ASSERT (st1.st_atime == st2.st_atime);
   ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
@@ -114,21 +99,64 @@ test_utimens (int (*func) (char const *, struct timespec const *))
     ASSERT (st2.st_mtime == Y2K);
     ASSERT (0 <= get_stat_mtime_ns (&st2));
     ASSERT (get_stat_mtime_ns (&st2) < BILLION);
     ASSERT (st2.st_mtime == Y2K);
     ASSERT (0 <= get_stat_mtime_ns (&st2));
     ASSERT (get_stat_mtime_ns (&st2) < BILLION);
+    if (check_ctime)
+      ASSERT (ctime_compare (&st1, &st2) < 0);
   }
 
   /* Play with UTIME_OMIT, UTIME_NOW.  */
   {
   }
 
   /* Play with UTIME_OMIT, UTIME_NOW.  */
   {
+    struct stat st3;
     struct timespec ts[2] = { { BILLION, UTIME_OMIT }, { 0, UTIME_NOW } };
     struct timespec ts[2] = { { BILLION, UTIME_OMIT }, { 0, UTIME_NOW } };
+    nap ();
     ASSERT (func (BASE "file", ts) == 0);
     ASSERT (func (BASE "file", ts) == 0);
-    ASSERT (stat (BASE "file", &st2) == 0);
-    ASSERT (st2.st_atime == Y2K);
-    ASSERT (0 <= get_stat_atime_ns (&st2));
-    ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
+    ASSERT (stat (BASE "file", &st3) == 0);
+    ASSERT (st3.st_atime == Y2K);
+    ASSERT (0 <= get_stat_atime_ns (&st3));
+    ASSERT (get_stat_atime_ns (&st3) < BILLION / 2);
     /* See comment above about this utimecmp call.  */
     /* See comment above about this utimecmp call.  */
-    ASSERT (0 <= utimecmp (BASE "file", &st2, &st1, UTIMECMP_TRUNCATE_SOURCE));
+    ASSERT (0 <= utimecmp (BASE "file", &st3, &st1, UTIMECMP_TRUNCATE_SOURCE));
+    if (check_ctime)
+      ASSERT (ctime_compare (&st2, &st3) < 0);
+    nap ();
+    ts[0].tv_nsec = 0;
+    ts[1].tv_nsec = UTIME_OMIT;
+    ASSERT (func (BASE "file", ts) == 0);
+    ASSERT (stat (BASE "file", &st2) == 0);
+    ASSERT (st2.st_atime == BILLION);
+    ASSERT (get_stat_atime_ns (&st2) == 0);
+    ASSERT (st3.st_mtime == st2.st_mtime);
+    ASSERT (get_stat_mtime_ns (&st3) == get_stat_mtime_ns (&st2));
+    if (check_ctime)
+      ASSERT (ctime_compare (&st3, &st2) < 0);
+  }
+
+  /* Make sure this dereferences symlinks.  */
+  if (symlink (BASE "file", BASE "link"))
+    {
+      ASSERT (unlink (BASE "file") == 0);
+      if (print)
+        fputs ("skipping test: symlinks not supported on this file system\n",
+               stderr);
+      return 77;
+    }
+  ASSERT (lstat (BASE "link", &st1) == 0);
+  ASSERT (st1.st_mtime != Y2K);
+  errno = 0;
+  ASSERT (func (BASE "link/", NULL) == -1);
+  ASSERT (errno == ENOTDIR);
+  {
+    struct timespec ts[2] = { { Y2K, 0 }, { Y2K, 0 } };
+    ASSERT (func (BASE "link", ts) == 0);
+    ASSERT (lstat (BASE "link", &st2) == 0);
+    /* Can't compare atimes, since lstat() changes symlink atime on cygwin.  */
+    ASSERT (st1.st_mtime == st2.st_mtime);
+    ASSERT (stat (BASE "link", &st2) == 0);
+    ASSERT (st2.st_mtime == Y2K);
+    ASSERT (get_stat_mtime_ns (&st2) == 0);
   }
 
   /* Cleanup.  */
   }
 
   /* Cleanup.  */
+  ASSERT (unlink (BASE "link") == 0);
   ASSERT (unlink (BASE "file") == 0);
   return 0;
 }
   ASSERT (unlink (BASE "file") == 0);
   return 0;
 }