Issue #1777412: strftime() accepts year >= 1 instead of year >= 1900
* With Visual Studio, year have to be in [1; 9999] * Add more tests on the year field
This commit is contained in:
parent
0dd06f4082
commit
73ea29cb03
|
@ -43,14 +43,8 @@ class TimeTestCase(unittest.TestCase):
|
||||||
# Make sure that strftime() checks the bounds of the various parts
|
# Make sure that strftime() checks the bounds of the various parts
|
||||||
#of the time tuple (0 is valid for *all* values).
|
#of the time tuple (0 is valid for *all* values).
|
||||||
|
|
||||||
# Check year [1900, max(int)]
|
# The year field is tested by other test cases above
|
||||||
self.assertRaises(ValueError, func,
|
|
||||||
(999, 1, 1, 0, 0, 0, 0, 1, -1))
|
|
||||||
if time.accept2dyear:
|
|
||||||
self.assertRaises(ValueError, func,
|
|
||||||
(-1, 1, 1, 0, 0, 0, 0, 1, -1))
|
|
||||||
self.assertRaises(ValueError, func,
|
|
||||||
(100, 1, 1, 0, 0, 0, 0, 1, -1))
|
|
||||||
# Check month [1, 12] + zero support
|
# Check month [1, 12] + zero support
|
||||||
self.assertRaises(ValueError, func,
|
self.assertRaises(ValueError, func,
|
||||||
(1900, -1, 1, 0, 0, 0, 0, 1, -1))
|
(1900, -1, 1, 0, 0, 0, 0, 1, -1))
|
||||||
|
@ -267,8 +261,10 @@ class TestLocale(unittest.TestCase):
|
||||||
# This should not cause an exception
|
# This should not cause an exception
|
||||||
time.strftime("%B", (2009,2,1,0,0,0,0,0,0))
|
time.strftime("%B", (2009,2,1,0,0,0,0,0,0))
|
||||||
|
|
||||||
class TestAccept2Year(unittest.TestCase):
|
|
||||||
accept2dyear = 1
|
class _BaseYearTest(unittest.TestCase):
|
||||||
|
accept2dyear = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.saved_accept2dyear = time.accept2dyear
|
self.saved_accept2dyear = time.accept2dyear
|
||||||
time.accept2dyear = self.accept2dyear
|
time.accept2dyear = self.accept2dyear
|
||||||
|
@ -277,10 +273,37 @@ class TestAccept2Year(unittest.TestCase):
|
||||||
time.accept2dyear = self.saved_accept2dyear
|
time.accept2dyear = self.saved_accept2dyear
|
||||||
|
|
||||||
def yearstr(self, y):
|
def yearstr(self, y):
|
||||||
# return time.strftime('%Y', (y,) + (0,) * 8)
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
class _TestAsctimeYear:
|
||||||
|
def yearstr(self, y):
|
||||||
return time.asctime((y,) + (0,) * 8).split()[-1]
|
return time.asctime((y,) + (0,) * 8).split()[-1]
|
||||||
|
|
||||||
def test_2dyear(self):
|
def test_large_year(self):
|
||||||
|
# Check that it doesn't crash with year > 9999
|
||||||
|
self.assertEqual(self.yearstr(12345), '12345')
|
||||||
|
self.assertEqual(self.yearstr(123456789), '123456789')
|
||||||
|
|
||||||
|
class _TestStrftimeYear:
|
||||||
|
def yearstr(self, y):
|
||||||
|
return time.strftime('%Y', (y,) + (0,) * 8).split()[-1]
|
||||||
|
|
||||||
|
def test_large_year(self):
|
||||||
|
# Just check that it doesn't crash with year > 9999: it may or may not
|
||||||
|
# raise an error depending on the OS and compiler
|
||||||
|
try:
|
||||||
|
self.yearstr(12345)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
self.yearstr(123456)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class _Test2dYear(_BaseYearTest):
|
||||||
|
accept2dyear = 1
|
||||||
|
|
||||||
|
def test_year(self):
|
||||||
with support.check_warnings():
|
with support.check_warnings():
|
||||||
self.assertEqual(self.yearstr(0), '2000')
|
self.assertEqual(self.yearstr(0), '2000')
|
||||||
self.assertEqual(self.yearstr(69), '1969')
|
self.assertEqual(self.yearstr(69), '1969')
|
||||||
|
@ -288,27 +311,41 @@ class TestAccept2Year(unittest.TestCase):
|
||||||
self.assertEqual(self.yearstr(99), '1999')
|
self.assertEqual(self.yearstr(99), '1999')
|
||||||
|
|
||||||
def test_invalid(self):
|
def test_invalid(self):
|
||||||
self.assertRaises(ValueError, self.yearstr, 999)
|
|
||||||
self.assertRaises(ValueError, self.yearstr, 100)
|
|
||||||
self.assertRaises(ValueError, self.yearstr, -1)
|
self.assertRaises(ValueError, self.yearstr, -1)
|
||||||
|
self.assertRaises(ValueError, self.yearstr, 100)
|
||||||
|
self.assertRaises(ValueError, self.yearstr, 999)
|
||||||
|
|
||||||
class TestAccept2YearBool(TestAccept2Year):
|
class _Test4dYear(_BaseYearTest):
|
||||||
accept2dyear = True
|
|
||||||
|
|
||||||
class TestDontAccept2Year(TestAccept2Year):
|
|
||||||
accept2dyear = 0
|
accept2dyear = 0
|
||||||
def test_2dyear(self):
|
|
||||||
self.assertEqual(self.yearstr(0), '0')
|
def test_year(self):
|
||||||
|
self.assertEqual(self.yearstr(1), '1')
|
||||||
self.assertEqual(self.yearstr(69), '69')
|
self.assertEqual(self.yearstr(69), '69')
|
||||||
self.assertEqual(self.yearstr(68), '68')
|
self.assertEqual(self.yearstr(68), '68')
|
||||||
self.assertEqual(self.yearstr(99), '99')
|
self.assertEqual(self.yearstr(99), '99')
|
||||||
self.assertEqual(self.yearstr(999), '999')
|
self.assertEqual(self.yearstr(999), '999')
|
||||||
self.assertEqual(self.yearstr(9999), '9999')
|
self.assertEqual(self.yearstr(9999), '9999')
|
||||||
|
|
||||||
def test_invalid(self):
|
class TestAsctimeAccept2dYear(_TestAsctimeYear, _Test2dYear):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class TestAccept2YearBad(TestAccept2Year):
|
class TestStrftimeAccept2dYear(_TestStrftimeYear, _Test2dYear):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestAsctime4dyear(_TestAsctimeYear, _Test4dYear):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear):
|
||||||
|
def test_bounds(self):
|
||||||
|
self.assertRaises(ValueError, self.yearstr, 0)
|
||||||
|
|
||||||
|
class Test2dyearBool(_TestAsctimeYear, _Test2dYear):
|
||||||
|
accept2dyear = True
|
||||||
|
|
||||||
|
class Test4dyearBool(_TestAsctimeYear, _Test4dYear):
|
||||||
|
accept2dyear = False
|
||||||
|
|
||||||
|
class TestAccept2YearBad(_TestAsctimeYear, _BaseYearTest):
|
||||||
class X:
|
class X:
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
raise RuntimeError('boo')
|
raise RuntimeError('boo')
|
||||||
|
@ -319,14 +356,17 @@ class TestAccept2YearBad(TestAccept2Year):
|
||||||
self.assertRaises(RuntimeError, self.yearstr, 200)
|
self.assertRaises(RuntimeError, self.yearstr, 200)
|
||||||
|
|
||||||
|
|
||||||
class TestDontAccept2YearBool(TestDontAccept2Year):
|
|
||||||
accept2dyear = False
|
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(TimeTestCase, TestLocale,
|
support.run_unittest(
|
||||||
TestAccept2Year, TestAccept2YearBool, TestAccept2YearBad,
|
TimeTestCase,
|
||||||
TestDontAccept2Year, TestDontAccept2YearBool)
|
TestLocale,
|
||||||
|
TestAsctimeAccept2dYear,
|
||||||
|
TestStrftimeAccept2dYear,
|
||||||
|
TestAsctime4dyear,
|
||||||
|
TestStrftime4dyear,
|
||||||
|
Test2dyearBool,
|
||||||
|
Test4dyearBool,
|
||||||
|
TestAccept2YearBad)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_main()
|
test_main()
|
||||||
|
|
|
@ -474,15 +474,21 @@ time_strftime(PyObject *self, PyObject *args)
|
||||||
else if (!gettmarg(tup, &buf) || !checktm(&buf))
|
else if (!gettmarg(tup, &buf) || !checktm(&buf))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* XXX: Reportedly, some systems have issues formating dates prior to year
|
#ifdef _MSC_VER
|
||||||
* 1000. These systems should be identified and this check should be
|
if (buf.tm_year + 1900 < 1 || 9999 < buf.tm_year + 1900) {
|
||||||
* moved to appropriate system specific section below. */
|
PyErr_Format(PyExc_ValueError,
|
||||||
if (buf.tm_year < -900) {
|
"strftime() requires year in [1; 9999]",
|
||||||
PyErr_Format(PyExc_ValueError, "year=%d is before 1900; "
|
|
||||||
"the strftime() method requires year >= 1900",
|
|
||||||
buf.tm_year + 1900);
|
buf.tm_year + 1900);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (buf.tm_year + 1900 < 1) {
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"strftime() requires year >= 1",
|
||||||
|
buf.tm_year + 1900);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Normalize tm_isdst just in case someone foolishly implements %Z
|
/* Normalize tm_isdst just in case someone foolishly implements %Z
|
||||||
based on the assumption that tm_isdst falls within the range of
|
based on the assumption that tm_isdst falls within the range of
|
||||||
|
|
Loading…
Reference in New Issue