[v3] tst: Provide Y2038 tests for mktime (tst-mktime4.c)

Message ID 20210127221601.30284-1-lukma@denx.de
State Superseded
Headers
Series [v3] tst: Provide Y2038 tests for mktime (tst-mktime4.c) |

Commit Message

Lukasz Majewski Jan. 27, 2021, 10:16 p.m. UTC
  This change adds new test to assess mktime's functionality.

To be more specific - following use cases are checked:
- Pass struct tm as epoch time
- Pass struct tm as value just before Y2038 threshold (returned
  value shall be 0x7FFFFFFF)
- Pass struct tm as the first value after Y2038 threshold
  (expected value - 0x80000000)

---
Changes for v2:
- Remove FAIL_UNSUPPORTED() when sizeof (time_t) <= 4
- Remove tzset () as it is already done in mktime ()
- Use TEST_COMPARE to check if correct result is received
- Use "TZ=:" glibc extension to guarantee UTC time zone
- Add two more checks - prepare struct tm in a way that mktime will
  return 0xFFFFFFFF and 0x100000000

Changes for v3:
- Remove .tm_wday and .tm_yday as are irrelevant
- Add (time_t) -1 cast when checking mktime return value
- Replace "executed" with "compiled".
- Use long long int as the exp_val type to avoid overflow compilation error
- Rename tm1 to tm32bitmax
- Define tm0, tmY2038, tm32bitmax as const
- Pass the pointer to copy of aforementioned structs to test_mktime_helper
---
 time/Makefile      |  2 +-
 time/tst-mktime4.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 time/tst-mktime4.c
  

Comments

Florian Weimer Feb. 7, 2021, 9:57 a.m. UTC | #1
* Lukasz Majewski:

> This change adds new test to assess mktime's functionality.

Commit suject prefix should probabily be “time”.

There are a few “mktime(” occurrences in the patch, they should be
”mktime (”.

> diff --git a/time/tst-mktime4.c b/time/tst-mktime4.c
> new file mode 100644
> index 0000000000..3be1b5b76c
> --- /dev/null
> +++ b/time/tst-mktime4.c

> +const struct tm tm0 = {
> +                 .tm_year = 70,
> +                 .tm_mon = 0,
> +                 .tm_mday = 1,
> +                 .tm_hour = 0,
> +                 .tm_min = 0,
> +                 .tm_sec = 0,
> +                 .tm_wday = 4,
> +                 .tm_yday = 0
> +};
> +
> +const struct tm tmY2038 = {
> +                     .tm_year = 138,
> +                     .tm_mon = 0,
> +                     .tm_mday = 19,
> +                     .tm_hour = 3,
> +                     .tm_min = 14,
> +                     .tm_sec = 7,
> +};
> +
> +const struct tm tm32bitmax = {
> +                     .tm_year = 206,
> +                     .tm_mon = 1,
> +                     .tm_mday = 7,
> +                     .tm_hour = 6,
> +                     .tm_min = 28,
> +                     .tm_sec = 15,
> +};

I think GNU style looks more lile this:

const struct tm tm0 =
  {
    .tm_year = 70,
    .tm_mon = 0,
    .tm_mday = 1,
    .tm_hour = 0,
    .tm_min = 0,
    .tm_sec = 0,
    .tm_wday = 4,
    .tm_yday = 0
  };

It has also been suggested that we should include a trailing “,” to
indicate that some struct members have been ommitted.

> +static
> +void test_mktime_helper (struct tm *tm, long long int exp_val)
> +{
> +  time_t result = mktime (tm);
> +  if (result == (time_t) -1)
> +    FAIL_EXIT1 ("*** mktime failed: %m");
> +
> +  TEST_COMPARE ((long long int) result, exp_val);
> +}

You could add a __LINE__ argument to make it clearer which subtest
failed.

The test itself looks okay to me.

Thanks,
Florian
  
Lukasz Majewski Feb. 8, 2021, 8:49 a.m. UTC | #2
Hi Florian,

> * Lukasz Majewski:
> 
> > This change adds new test to assess mktime's functionality.  
> 
> Commit suject prefix should probabily be “time”.

Ok.

> 
> There are a few “mktime(” occurrences in the patch, they should be
> ”mktime (”.

Ok.

> 
> > diff --git a/time/tst-mktime4.c b/time/tst-mktime4.c
> > new file mode 100644
> > index 0000000000..3be1b5b76c
> > --- /dev/null
> > +++ b/time/tst-mktime4.c  
> 
> > +const struct tm tm0 = {
> > +                 .tm_year = 70,
> > +                 .tm_mon = 0,
> > +                 .tm_mday = 1,
> > +                 .tm_hour = 0,
> > +                 .tm_min = 0,
> > +                 .tm_sec = 0,
> > +                 .tm_wday = 4,
> > +                 .tm_yday = 0
> > +};
> > +
> > +const struct tm tmY2038 = {
> > +                     .tm_year = 138,
> > +                     .tm_mon = 0,
> > +                     .tm_mday = 19,
> > +                     .tm_hour = 3,
> > +                     .tm_min = 14,
> > +                     .tm_sec = 7,
> > +};
> > +
> > +const struct tm tm32bitmax = {
> > +                     .tm_year = 206,
> > +                     .tm_mon = 1,
> > +                     .tm_mday = 7,
> > +                     .tm_hour = 6,
> > +                     .tm_min = 28,
> > +                     .tm_sec = 15,
> > +};  
> 
> I think GNU style looks more lile this:
> 
> const struct tm tm0 =
>   {
>     .tm_year = 70,
>     .tm_mon = 0,
>     .tm_mday = 1,
>     .tm_hour = 0,
>     .tm_min = 0,
>     .tm_sec = 0,
>     .tm_wday = 4,
>     .tm_yday = 0
>   };
> 
> It has also been suggested that we should include a trailing “,” to
> indicate that some struct members have been ommitted.

Thanks for providing this input.

> 
> > +static
> > +void test_mktime_helper (struct tm *tm, long long int exp_val)
> > +{
> > +  time_t result = mktime (tm);
> > +  if (result == (time_t) -1)
> > +    FAIL_EXIT1 ("*** mktime failed: %m");
> > +
> > +  TEST_COMPARE ((long long int) result, exp_val);
> > +}  
> 
> You could add a __LINE__ argument to make it clearer which subtest
> failed.

Ok, I will replace TEST_COMPARE with if and FAIL_EXIT1() macro with
__LINE__.

> 
> The test itself looks okay to me.
> 
> Thanks,
> Florian




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
  
Florian Weimer Feb. 8, 2021, 9:15 a.m. UTC | #3
* Lukasz Majewski:

>> > +static
>> > +void test_mktime_helper (struct tm *tm, long long int exp_val)
>> > +{
>> > +  time_t result = mktime (tm);
>> > +  if (result == (time_t) -1)
>> > +    FAIL_EXIT1 ("*** mktime failed: %m");
>> > +
>> > +  TEST_COMPARE ((long long int) result, exp_val);
>> > +}  
>> 
>> You could add a __LINE__ argument to make it clearer which subtest
>> failed.
>
> Ok, I will replace TEST_COMPARE with if and FAIL_EXIT1() macro with
> __LINE__.

Just to be clear, __LINE__ needs to be passed to test_mktime_helper.

Thanks,
Florian
  
Lukasz Majewski Feb. 8, 2021, 2:46 p.m. UTC | #4
Hi Florian,

> * Lukasz Majewski:
> 
> >> > +static
> >> > +void test_mktime_helper (struct tm *tm, long long int exp_val)
> >> > +{
> >> > +  time_t result = mktime (tm);
> >> > +  if (result == (time_t) -1)
> >> > +    FAIL_EXIT1 ("*** mktime failed: %m");
> >> > +
> >> > +  TEST_COMPARE ((long long int) result, exp_val);
> >> > +}    
> >> 
> >> You could add a __LINE__ argument to make it clearer which subtest
> >> failed.  
> >
> > Ok, I will replace TEST_COMPARE with if and FAIL_EXIT1() macro with
> > __LINE__.  
> 
> Just to be clear, __LINE__ needs to be passed to test_mktime_helper.
> 

Yes. You are obviously right here.

> Thanks,
> Florian




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
  

Patch

diff --git a/time/Makefile b/time/Makefile
index 7de2ce0196..f214d001f5 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -51,7 +51,7 @@  tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
 	   tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \
 	   tst-adjtime tst-clock-y2038 tst-clock2-y2038 \
 	   tst-cpuclock1-y2038 tst-clock_nanosleep-y2038 tst-clock_settime \
-	   tst-clock_adjtime tst-ctime tst-difftime
+	   tst-clock_adjtime tst-ctime tst-difftime tst-mktime4
 
 include ../Rules
 
diff --git a/time/tst-mktime4.c b/time/tst-mktime4.c
new file mode 100644
index 0000000000..3be1b5b76c
--- /dev/null
+++ b/time/tst-mktime4.c
@@ -0,0 +1,99 @@ 
+/* Test for mktime (4)
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <time.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+const struct tm tm0 = {
+                 .tm_year = 70,
+                 .tm_mon = 0,
+                 .tm_mday = 1,
+                 .tm_hour = 0,
+                 .tm_min = 0,
+                 .tm_sec = 0,
+                 .tm_wday = 4,
+                 .tm_yday = 0
+};
+
+const struct tm tmY2038 = {
+                     .tm_year = 138,
+                     .tm_mon = 0,
+                     .tm_mday = 19,
+                     .tm_hour = 3,
+                     .tm_min = 14,
+                     .tm_sec = 7,
+};
+
+const struct tm tm32bitmax = {
+                     .tm_year = 206,
+                     .tm_mon = 1,
+                     .tm_mday = 7,
+                     .tm_hour = 6,
+                     .tm_min = 28,
+                     .tm_sec = 15,
+};
+
+static
+void test_mktime_helper (struct tm *tm, long long int exp_val)
+{
+  time_t result = mktime (tm);
+  if (result == (time_t) -1)
+    FAIL_EXIT1 ("*** mktime failed: %m");
+
+  TEST_COMPARE ((long long int) result, exp_val);
+}
+
+static int
+do_test (void)
+{
+  struct tm t;
+  /* Use glibc time zone extension "TZ=:" to to guarantee that UTC
+     without leap seconds is used for the test.  */
+  TEST_VERIFY_EXIT (setenv ("TZ", ":", 1) == 0);
+
+  /* Check that mktime(1970-01-01 00:00:00) returns 0.  */
+  t = tm0;
+  test_mktime_helper (&t, 0);
+
+  /* Check that mktime(2038-01-19 03:14:07) returns 0x7FFFFFFF.  */
+  t = tmY2038;
+  test_mktime_helper (&t, 0x7fffffff);
+
+  if (sizeof (time_t) > 4)
+    {
+      /* Check that mktime(2038-01-19 03:14:08) returns 0x80000000
+         (time_t overflow).  */
+      t = tmY2038;
+      t.tm_sec++;
+      test_mktime_helper (&t, 0x80000000);
+
+      /* Check that mktime(2106-02-07 06:28:15) returns 0xFFFFFFFF.  */
+      t = tm32bitmax;
+      test_mktime_helper (&t, 0xFFFFFFFF);
+
+      /* Check that mktime(2106-02-07 06:28:16) returns 0x100000000.  */
+      t = tm32bitmax;
+      t.tm_sec++;
+      test_mktime_helper (&t, 0x100000000);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>