From 9c72f9b30a60d09c10b6cde23bd4b0546c6947af Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Sep 2015 09:10:14 +0200 Subject: [PATCH] Fix test_time on Windows * Filter values which would overflow on conversion to the C long type (for timeval.tv_sec). * Adjust also the message of OverflowError on PyTime conversions * test_time: add debug information if a timestamp conversion fails --- Lib/test/test_time.py | 33 ++++++++++++++++++++++++--------- Python/pytime.c | 28 ++++++++-------------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index bd697aeb13b..7f1613b7ce2 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -756,10 +756,15 @@ class CPyTimeTestCase: context.rounding = decimal_rnd for value in valid_values: - expected = expected_func(value) - self.assertEqual(pytime_converter(value, time_rnd), + debug_info = {'value': value, 'rounding': decimal_rnd} + try: + result = pytime_converter(value, time_rnd) + expected = expected_func(value) + except Exception as exc: + self.fail("Error on timestamp conversion: %s" % debug_info) + self.assertEqual(result, expected, - {'value': value, 'rounding': decimal_rnd}) + debug_info) # test overflow ns = self.OVERFLOW_SECONDS * SEC_TO_NS @@ -770,14 +775,15 @@ class CPyTimeTestCase: with self.assertRaises(OverflowError): pytime_converter(value, time_rnd) - def check_int_rounding(self, pytime_converter, expected_func, unit_to_sec=1, - value_filter=None): + def check_int_rounding(self, pytime_converter, expected_func, + unit_to_sec=1, value_filter=None): self._check_rounding(pytime_converter, expected_func, False, unit_to_sec, value_filter) - def check_float_rounding(self, pytime_converter, expected_func, unit_to_sec=1): + def check_float_rounding(self, pytime_converter, expected_func, + unit_to_sec=1, value_filter=None): self._check_rounding(pytime_converter, expected_func, - True, unit_to_sec) + True, unit_to_sec, value_filter) def decimal_round(self, x): d = decimal.Decimal(x) @@ -845,9 +851,19 @@ class TestCPyTime(CPyTimeTestCase, unittest.TestCase): us = us_converter(ns) return divmod(us, SEC_TO_US) + if sys.platform == 'win32': + from _testcapi import LONG_MIN, LONG_MAX + + # On Windows, timeval.tv_sec type is a C long + def seconds_filter(secs): + return LONG_MIN <= secs <= LONG_MAX + else: + seconds_filter = None + self.check_int_rounding(PyTime_AsTimeval, timeval_converter, - NS_TO_SEC) + NS_TO_SEC, + value_filter=seconds_filter) @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'), 'need _testcapi.PyTime_AsTimespec') @@ -927,6 +943,5 @@ class TestOldPyTime(CPyTimeTestCase, unittest.TestCase): self.create_converter(SEC_TO_NS)) - if __name__ == "__main__": unittest.main() diff --git a/Python/pytime.c b/Python/pytime.c index 4c940c98f12..243f756f3d4 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -288,18 +288,21 @@ _PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round, else { #ifdef HAVE_LONG_LONG PY_LONG_LONG sec; - sec = PyLong_AsLongLong(obj); assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t)); + + sec = PyLong_AsLongLong(obj); #else long sec; - sec = PyLong_AsLong(obj); assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t)); + + sec = PyLong_AsLong(obj); #endif if (sec == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) _PyTime_overflow(); return -1; } + *t = sec * unit_to_ns; if (*t / unit_to_ns != sec) { _PyTime_overflow(); @@ -404,27 +407,12 @@ _PyTime_AsTimeval_impl(_PyTime_t t, struct timeval *tv, _PyTime_round_t round, ns = t % SEC_TO_NS; #ifdef MS_WINDOWS - /* On Windows, timeval.tv_sec is a long (32 bit), - whereas time_t can be 64-bit. */ - assert(sizeof(tv->tv_sec) == sizeof(long)); -#if SIZEOF_TIME_T > SIZEOF_LONG - if (secs > LONG_MAX) { - secs = LONG_MAX; - res = -1; - } - else if (secs < LONG_MIN) { - secs = LONG_MIN; - res = -1; - } -#endif tv->tv_sec = (long)secs; #else - /* On OpenBSD 5.4, timeval.tv_sec is a long. - Example: long is 64-bit, whereas time_t is 32-bit. */ tv->tv_sec = secs; +#endif if ((_PyTime_t)tv->tv_sec != secs) res = -1; -#endif usec = (int)_PyTime_Divide(ns, US_TO_NS, round); if (usec < 0) { @@ -440,7 +428,7 @@ _PyTime_AsTimeval_impl(_PyTime_t t, struct timeval *tv, _PyTime_round_t round, tv->tv_usec = usec; if (res && raise) - _PyTime_overflow(); + error_time_t_overflow(); return res; } @@ -473,7 +461,7 @@ _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts) ts->tv_nsec = nsec; if ((_PyTime_t)ts->tv_sec != secs) { - _PyTime_overflow(); + error_time_t_overflow(); return -1; } return 0;