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
This commit is contained in:
Victor Stinner 2015-09-10 09:10:14 +02:00
parent 4f1f6e4618
commit 9c72f9b30a
2 changed files with 32 additions and 29 deletions

View File

@ -756,10 +756,15 @@ class CPyTimeTestCase:
context.rounding = decimal_rnd context.rounding = decimal_rnd
for value in valid_values: for value in valid_values:
expected = expected_func(value) debug_info = {'value': value, 'rounding': decimal_rnd}
self.assertEqual(pytime_converter(value, time_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, expected,
{'value': value, 'rounding': decimal_rnd}) debug_info)
# test overflow # test overflow
ns = self.OVERFLOW_SECONDS * SEC_TO_NS ns = self.OVERFLOW_SECONDS * SEC_TO_NS
@ -770,14 +775,15 @@ class CPyTimeTestCase:
with self.assertRaises(OverflowError): with self.assertRaises(OverflowError):
pytime_converter(value, time_rnd) pytime_converter(value, time_rnd)
def check_int_rounding(self, pytime_converter, expected_func, unit_to_sec=1, def check_int_rounding(self, pytime_converter, expected_func,
value_filter=None): unit_to_sec=1, value_filter=None):
self._check_rounding(pytime_converter, expected_func, self._check_rounding(pytime_converter, expected_func,
False, unit_to_sec, value_filter) 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, self._check_rounding(pytime_converter, expected_func,
True, unit_to_sec) True, unit_to_sec, value_filter)
def decimal_round(self, x): def decimal_round(self, x):
d = decimal.Decimal(x) d = decimal.Decimal(x)
@ -845,9 +851,19 @@ class TestCPyTime(CPyTimeTestCase, unittest.TestCase):
us = us_converter(ns) us = us_converter(ns)
return divmod(us, SEC_TO_US) 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, self.check_int_rounding(PyTime_AsTimeval,
timeval_converter, timeval_converter,
NS_TO_SEC) NS_TO_SEC,
value_filter=seconds_filter)
@unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'), @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'),
'need _testcapi.PyTime_AsTimespec') 'need _testcapi.PyTime_AsTimespec')
@ -927,6 +943,5 @@ class TestOldPyTime(CPyTimeTestCase, unittest.TestCase):
self.create_converter(SEC_TO_NS)) self.create_converter(SEC_TO_NS))
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -288,18 +288,21 @@ _PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round,
else { else {
#ifdef HAVE_LONG_LONG #ifdef HAVE_LONG_LONG
PY_LONG_LONG sec; PY_LONG_LONG sec;
sec = PyLong_AsLongLong(obj);
assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t)); assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t));
sec = PyLong_AsLongLong(obj);
#else #else
long sec; long sec;
sec = PyLong_AsLong(obj);
assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t)); assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t));
sec = PyLong_AsLong(obj);
#endif #endif
if (sec == -1 && PyErr_Occurred()) { if (sec == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) if (PyErr_ExceptionMatches(PyExc_OverflowError))
_PyTime_overflow(); _PyTime_overflow();
return -1; return -1;
} }
*t = sec * unit_to_ns; *t = sec * unit_to_ns;
if (*t / unit_to_ns != sec) { if (*t / unit_to_ns != sec) {
_PyTime_overflow(); _PyTime_overflow();
@ -404,27 +407,12 @@ _PyTime_AsTimeval_impl(_PyTime_t t, struct timeval *tv, _PyTime_round_t round,
ns = t % SEC_TO_NS; ns = t % SEC_TO_NS;
#ifdef MS_WINDOWS #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; tv->tv_sec = (long)secs;
#else #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; tv->tv_sec = secs;
#endif
if ((_PyTime_t)tv->tv_sec != secs) if ((_PyTime_t)tv->tv_sec != secs)
res = -1; res = -1;
#endif
usec = (int)_PyTime_Divide(ns, US_TO_NS, round); usec = (int)_PyTime_Divide(ns, US_TO_NS, round);
if (usec < 0) { if (usec < 0) {
@ -440,7 +428,7 @@ _PyTime_AsTimeval_impl(_PyTime_t t, struct timeval *tv, _PyTime_round_t round,
tv->tv_usec = usec; tv->tv_usec = usec;
if (res && raise) if (res && raise)
_PyTime_overflow(); error_time_t_overflow();
return res; return res;
} }
@ -473,7 +461,7 @@ _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
ts->tv_nsec = nsec; ts->tv_nsec = nsec;
if ((_PyTime_t)ts->tv_sec != secs) { if ((_PyTime_t)ts->tv_sec != secs) {
_PyTime_overflow(); error_time_t_overflow();
return -1; return -1;
} }
return 0; return 0;