|
| 1 | +"""Encoder-side tests for ``_iso8601_from_datetime``. |
| 2 | +
|
| 3 | +The decode side (``_datetime_from_iso8601``) has explicit error-path |
| 4 | +tests; the encoder was only exercised by integration tests. These unit |
| 5 | +tests pin the microsecond padding, tz-offset sign/magnitude, and the |
| 6 | +``date``-vs-``datetime`` fall-through so a regression in any branch |
| 7 | +surfaces quickly. |
| 8 | +""" |
| 9 | + |
| 10 | +import datetime |
| 11 | + |
| 12 | +from dqlitedbapi.types import _iso8601_from_datetime |
| 13 | + |
| 14 | + |
| 15 | +class TestIso8601FromDatetime: |
| 16 | + def test_datetime_without_microseconds(self) -> None: |
| 17 | + d = datetime.datetime(2025, 1, 1, 12, 0, 0) |
| 18 | + assert _iso8601_from_datetime(d) == "2025-01-01 12:00:00" |
| 19 | + |
| 20 | + def test_datetime_with_microseconds_zero_padded(self) -> None: |
| 21 | + d = datetime.datetime(2025, 1, 1, 12, 0, 0, microsecond=7) |
| 22 | + # Six-digit padded microseconds. |
| 23 | + assert _iso8601_from_datetime(d) == "2025-01-01 12:00:00.000007" |
| 24 | + |
| 25 | + def test_datetime_with_six_digit_microseconds(self) -> None: |
| 26 | + d = datetime.datetime(2025, 1, 1, 12, 0, 0, microsecond=999999) |
| 27 | + assert _iso8601_from_datetime(d) == "2025-01-01 12:00:00.999999" |
| 28 | + |
| 29 | + def test_naive_datetime_has_no_offset(self) -> None: |
| 30 | + """Naive datetimes emit the bare ISO string (no trailing offset).""" |
| 31 | + d = datetime.datetime(2025, 1, 1, 12, 0, 0) |
| 32 | + result = _iso8601_from_datetime(d) |
| 33 | + assert "+" not in result and result.count("-") == 2 |
| 34 | + |
| 35 | + def test_utc_offset_emitted_as_plus_zero(self) -> None: |
| 36 | + d = datetime.datetime(2025, 1, 1, 12, 0, 0, tzinfo=datetime.UTC) |
| 37 | + result = _iso8601_from_datetime(d) |
| 38 | + assert result.endswith("+00:00") |
| 39 | + |
| 40 | + def test_positive_offset(self) -> None: |
| 41 | + tz = datetime.timezone(datetime.timedelta(hours=5, minutes=30)) |
| 42 | + d = datetime.datetime(2025, 1, 1, 12, 0, 0, tzinfo=tz) |
| 43 | + assert _iso8601_from_datetime(d).endswith("+05:30") |
| 44 | + |
| 45 | + def test_negative_offset(self) -> None: |
| 46 | + tz = datetime.timezone(datetime.timedelta(hours=-5, minutes=-30)) |
| 47 | + d = datetime.datetime(2025, 1, 1, 12, 0, 0, tzinfo=tz) |
| 48 | + assert _iso8601_from_datetime(d).endswith("-05:30") |
| 49 | + |
| 50 | + def test_negative_offset_with_microseconds(self) -> None: |
| 51 | + tz = datetime.timezone(datetime.timedelta(hours=-8)) |
| 52 | + d = datetime.datetime(2025, 6, 15, 9, 30, 45, microsecond=42, tzinfo=tz) |
| 53 | + assert _iso8601_from_datetime(d) == "2025-06-15 09:30:45.000042-08:00" |
| 54 | + |
| 55 | + def test_date_only_takes_fall_through_branch(self) -> None: |
| 56 | + """``date`` (not ``datetime``) must produce the short YYYY-MM-DD |
| 57 | + form via the ``isoformat()`` fall-through, not the datetime |
| 58 | + branch that would call strftime with time components. |
| 59 | + """ |
| 60 | + d = datetime.date(2025, 1, 1) |
| 61 | + assert _iso8601_from_datetime(d) == "2025-01-01" |
0 commit comments