[glib] gdatetime test: don't assume that time stands still



commit 472dee39097881502bb593eb2effe37b3b6064a2
Author: Simon McVittie <simon mcvittie collabora co uk>
Date:   Fri May 8 16:38:33 2015 +0100

    gdatetime test: don't assume that time stands still
    
    If we call time(NULL), then do something (however trivial), then call
    g_date_time_new_now_utc(), they do not necessarily share a seconds
    value. Let's say the gmtime call takes 2ms. time(NULL) could
    return xx:xx:23 when the time is actually xx:xx:23.999999, resulting
    in the g_date_time_new_now_utc() happening at xx:xx:24.000001. This is
    unlikely, but did happen to me in a parallel build:
    
    GLib:ERROR:.../glib/tests/gdatetime.c:674:test_GDateTime_now_utc: assertion failed (tm.tm_sec == 
g_date_time_get_second (dt)): (23 == 24)
    
    A similar argument applies to the rollover from xx:23:59.999999 to
    xx:24:00, so comparing seconds with a 1s "fuzz" or a >= comparison
    is not sufficient; and so on into higher-order fields.
    
    I haven't seen the other tests that use _now() fail in the same way,
    but they could.
    
    Bug: https://bugzilla.gnome.org/show_bug.cgi?id=749080
    Reviewed-by: Philip Withnall <philip withnall collabora co uk>
    Signed-off-by: Simon McVittie <simon mcvittie collabora co uk>

 glib/tests/gdatetime.c |   79 +++++++++++++++++++++++++++++++++++------------
 1 files changed, 59 insertions(+), 20 deletions(-)
---
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index f615299..4241f7b 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -70,19 +70,32 @@ test_GDateTime_now (void)
 {
   GDateTime *dt;
   struct tm tm;
+  time_t before;
+  time_t after;
+
+  /* before <= dt.to_unix() <= after, but the inequalities might not be
+   * equality if we're close to the boundary between seconds.
+   * We loop until before == after (and hence dt.to_unix() should equal both)
+   * to guard against that. */
+  do
+    {
+      before = time (NULL);
 
-  memset (&tm, 0, sizeof (tm));
-  get_localtime_tm (time (NULL), &tm);
+      memset (&tm, 0, sizeof (tm));
+      get_localtime_tm (before, &tm);
 
-  dt = g_date_time_new_now_local ();
+      dt = g_date_time_new_now_local ();
+
+      after = time (NULL);
+    }
+  while (before != after);
 
   g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
   g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, tm.tm_mday);
   g_assert_cmpint (g_date_time_get_hour (dt), ==, tm.tm_hour);
   g_assert_cmpint (g_date_time_get_minute (dt), ==, tm.tm_min);
-  /* XXX we need some fuzzyness here */
-  g_assert_cmpint (g_date_time_get_second (dt), >=, tm.tm_sec);
+  g_assert_cmpint (g_date_time_get_second (dt), ==, tm.tm_sec);
 
   g_date_time_unref (dt);
 }
@@ -649,23 +662,35 @@ static void
 test_GDateTime_now_utc (void)
 {
   GDateTime *dt;
-  time_t     t;
   struct tm  tm;
+  time_t     t;
+  time_t     after;
 
-  t = time (NULL);
+  /* t <= dt.to_unix() <= after, but the inequalities might not be
+   * equality if we're close to the boundary between seconds.
+   * We loop until t == after (and hence dt.to_unix() should equal both)
+   * to guard against that. */
+  do
+    {
+      t = time (NULL);
 #ifdef HAVE_GMTIME_R
-  gmtime_r (&t, &tm);
+      gmtime_r (&t, &tm);
 #else
-  {
-    struct tm *tmp = gmtime (&t);
-    /* Assume gmtime() can't fail as we got t from time(NULL). (Note
-     * that on Windows, gmtime() *is* MT-safe, it uses a thread-local
-     * buffer.)
-     */
-    memcpy (&tm, tmp, sizeof (struct tm));
-  }
+      {
+        struct tm *tmp = gmtime (&t);
+        /* Assume gmtime() can't fail as we got t from time(NULL). (Note
+         * that on Windows, gmtime() *is* MT-safe, it uses a thread-local
+         * buffer.)
+         */
+        memcpy (&tm, tmp, sizeof (struct tm));
+      }
 #endif
-  dt = g_date_time_new_now_utc ();
+      dt = g_date_time_new_now_utc ();
+
+      after = time (NULL);
+    }
+  while (t != after);
+
   g_assert_cmpint (tm.tm_year + 1900, ==, g_date_time_get_year (dt));
   g_assert_cmpint (tm.tm_mon + 1, ==, g_date_time_get_month (dt));
   g_assert_cmpint (tm.tm_mday, ==, g_date_time_get_day_of_month (dt));
@@ -742,10 +767,24 @@ test_GDateTime_to_timeval (void)
 static void
 test_GDateTime_to_local (void)
 {
-  GDateTime *utc, *now, *dt;
+  GDateTime *utc = NULL, *now = NULL, *dt;
+  time_t before, after;
+
+  /* before <= utc.to_unix() <= now.to_unix() <= after, but the inequalities
+   * might not be equality if we're close to the boundary between seconds.
+   * We loop until before == after (and hence the GDateTimes should match)
+   * to guard against that. */
+  do
+    {
+      before = time (NULL);
+      g_clear_pointer (&utc, g_date_time_unref);
+      g_clear_pointer (&now, g_date_time_unref);
+      utc = g_date_time_new_now_utc ();
+      now = g_date_time_new_now_local ();
+      after = time (NULL);
+    }
+  while (before != after);
 
-  utc = g_date_time_new_now_utc ();
-  now = g_date_time_new_now_local ();
   dt = g_date_time_to_local (utc);
 
   g_assert_cmpint (g_date_time_get_year (now), ==, g_date_time_get_year (dt));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]