pyo3/examples/rustapi_module/tests/test_datetime.py

266 lines
6.3 KiB
Python

import rustapi_module.datetime as rdt
import sys
import datetime as pdt
import pytest
from hypothesis import given
from hypothesis import strategies as st
from hypothesis.strategies import dates, datetimes
# Constants
def _get_utc():
timezone = getattr(pdt, 'timezone', None)
if timezone:
return timezone.utc
else:
class UTC(pdt.tzinfo):
def utcoffset(self, dt):
return pdt.timedelta(0)
def dst(self, dt):
return pdt.timedelta(0)
def tzname(self, dt):
return "UTC"
return UTC()
UTC = _get_utc()
MAX_SECONDS = int(pdt.timedelta.max.total_seconds())
MIN_SECONDS = int(pdt.timedelta.min.total_seconds())
try:
MAX_DAYS = pdt.timedelta.max // pdt.timedelta(days=1)
MIN_DAYS = pdt.timedelta.min // pdt.timedelta(days=1)
except Exception:
# Python 2 compatibility
MAX_DAYS = MAX_SECONDS // pdt.timedelta(days=1).total_seconds()
MIN_DAYS = MIN_SECONDS // pdt.timedelta(days=1).total_seconds()
MAX_MICROSECONDS = int(pdt.timedelta.max.total_seconds() * 1e6)
MIN_MICROSECONDS = int(pdt.timedelta.min.total_seconds() * 1e6)
HAS_FOLD = getattr(pdt.datetime, 'fold', False)
# Helper functions
get_timestamp = getattr(pdt.datetime, 'timestamp', None)
if get_timestamp is None:
def get_timestamp(dt):
# Python 2 compatibility
return (dt - pdt.datetime(1970, 1, 1)).total_seconds()
xfail_date_bounds = pytest.mark.xfail(sys.version_info < (3, 6),
reason="Date bounds were not checked in the C constructor prior to version 3.6")
# Tests
def test_date():
assert rdt.make_date(2017, 9, 1) == pdt.date(2017, 9, 1)
@given(d=st.dates())
def test_date_accessors(d):
act = rdt.get_date_tuple(d)
exp = (d.year, d.month, d.day)
assert act == exp
@xfail_date_bounds
def test_invalid_date_fails():
with pytest.raises(ValueError):
rdt.make_date(2017, 2, 30)
@given(d=dates())
def test_date_from_timestamp(d):
ts = get_timestamp(pdt.datetime.combine(d, pdt.time(0)))
assert rdt.date_from_timestamp(int(ts)) == pdt.date.fromtimestamp(ts)
@pytest.mark.parametrize('args, kwargs', [
((0, 0, 0, 0, None), {}),
((1, 12, 14, 124731), {}),
((1, 12, 14, 124731), {'tzinfo': UTC}),
])
def test_time(args, kwargs):
act = rdt.make_time(*args, **kwargs)
exp = pdt.time(*args, **kwargs)
assert act == exp
assert act.tzinfo is exp.tzinfo
@given(t=st.times())
def test_time(t):
act = rdt.get_time_tuple(t)
exp = (t.hour, t.minute, t.second, t.microsecond)
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@given(t=st.times())
def test_time_fold(t):
t_nofold = t.replace(fold=0)
t_fold = t.replace(fold=1)
for t in (t_nofold, t_fold):
act = rdt.get_time_tuple_fold(t)
exp = (t.hour, t.minute, t.second, t.microsecond, t.fold)
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@pytest.mark.parametrize('fold', [False, True])
def test_time_fold(fold):
t = rdt.time_with_fold(0, 0, 0, 0, None, fold)
assert t.fold == fold
@pytest.mark.xfail
@pytest.mark.parametrize('args', [
(-1, 0, 0, 0),
(0, -1, 0, 0),
(0, 0, -1, 0),
(0, 0, 0, -1),
])
def test_invalid_time_fails_xfail(args):
with pytest.raises(ValueError):
rdt.make_time(*args)
@xfail_date_bounds
@pytest.mark.parametrize('args', [
(24, 0, 0, 0),
(25, 0, 0, 0),
(0, 60, 0, 0),
(0, 61, 0, 0),
(0, 0, 60, 0),
(0, 0, 61, 0),
(0, 0, 0, 1000000)
])
def test_invalid_time_fails(args):
with pytest.raises(ValueError):
rdt.make_time(*args)
@pytest.mark.parametrize('args', [
('0', 0, 0, 0),
(0, '0', 0, 0),
(0, 0, '0', 0),
(0, 0, 0, '0'),
(0, 0, 0, 0, 'UTC')
])
def test_time_typeerror(args):
with pytest.raises(TypeError):
rdt.make_time(*args)
@pytest.mark.parametrize('args, kwargs', [
((2017, 9, 1, 12, 45, 30, 0), {}),
((2017, 9, 1, 12, 45, 30, 0), {'tzinfo': UTC}),
])
def test_datetime(args, kwargs):
act = rdt.make_datetime(*args, **kwargs)
exp = pdt.datetime(*args, **kwargs)
assert act == exp
assert act.tzinfo is exp.tzinfo
@given(dt=st.datetimes())
def test_datetime_tuple(dt):
act = rdt.get_datetime_tuple(dt)
exp = dt.timetuple()[0:6] + (dt.microsecond, )
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@given(dt=st.datetimes())
def test_datetime_tuple_fold(dt):
dt_fold = dt.replace(fold=1)
dt_nofold = dt.replace(fold=0)
for dt in (dt_fold, dt_nofold):
act = rdt.get_datetime_tuple_fold(dt)
exp = dt.timetuple()[0:6] + (dt.microsecond, dt.fold)
assert act == exp
@xfail_date_bounds
def test_invalid_datetime_fails():
with pytest.raises(ValueError):
rdt.make_datetime(2011, 1, 42, 0, 0, 0, 0)
def test_datetime_typeerror():
with pytest.raises(TypeError):
rdt.make_datetime('2011', 1, 1, 0, 0, 0, 0)
@given(dt=datetimes())
def test_datetime_from_timestamp(dt):
ts = get_timestamp(dt)
assert rdt.datetime_from_timestamp(ts) == pdt.datetime.fromtimestamp(ts)
def test_datetime_from_timestamp_tzinfo():
d1 = rdt.datetime_from_timestamp(0, tz=UTC)
d2 = rdt.datetime_from_timestamp(0, tz=UTC)
assert d1 == d2
assert d1.tzinfo is d2.tzinfo
@pytest.mark.parametrize('args', [
(0, 0, 0),
(1, 0, 0),
(-1, 0, 0),
(0, 1, 0),
(0, -1, 0),
(1, -1, 0),
(-1, 1, 0),
(0, 0, 123456),
(0, 0, -123456),
])
def test_delta(args):
act = pdt.timedelta(*args)
exp = rdt.make_delta(*args)
assert act == exp
@given(td=st.timedeltas())
def test_delta_accessors(td):
act = rdt.get_delta_tuple(td)
exp = (td.days, td.seconds, td.microseconds)
assert act == exp
@pytest.mark.parametrize('args,err_type', [
((MAX_DAYS + 1, 0, 0), OverflowError),
((MIN_DAYS - 1, 0, 0), OverflowError),
((0, MAX_SECONDS + 1, 0), OverflowError),
((0, MIN_SECONDS - 1, 0), OverflowError),
((0, 0, MAX_MICROSECONDS + 1), OverflowError),
((0, 0, MIN_MICROSECONDS - 1), OverflowError),
(('0', 0, 0), TypeError),
((0, '0', 0), TypeError),
((0, 0, '0'), TypeError),
])
def test_delta_err(args, err_type):
with pytest.raises(err_type):
rdt.make_delta(*args)
def test_issue_219():
rdt.issue_219()