|
| 1 | +from datetime import datetime, timezone |
| 2 | +from uuid import UUID |
1 | 3 | import pytest |
2 | 4 | import uuid6 |
3 | 5 |
|
@@ -142,3 +144,61 @@ def test_uuid_property() -> None: |
142 | 144 | assert isinstance(typeid.uuid, uuid6.UUID) |
143 | 145 | assert typeid.uuid.version == uuid.version == 7 |
144 | 146 | assert typeid.uuid.time == uuid.time |
| 147 | + |
| 148 | + |
| 149 | +def test_created_at_none_for_nil_uuid_suffix(): |
| 150 | + tid = TypeID(prefix="x", suffix="00000000000000000000000000") |
| 151 | + assert tid.created_at is None |
| 152 | + |
| 153 | + |
| 154 | +def test_created_at_none_for_non_v7_uuid_v4(): |
| 155 | + # UUIDv4 (random) must not claim created_at |
| 156 | + u = UUID("550e8400-e29b-41d4-a716-446655440000") # version 4 |
| 157 | + tid = TypeID.from_uuid(u, prefix="x") |
| 158 | + assert tid.created_at is None |
| 159 | + |
| 160 | + |
| 161 | +def test_created_at_is_utc_for_uuid7_generated_typeid(): |
| 162 | + # Default TypeID generation should be UUIDv7; then created_at must be present and UTC |
| 163 | + tid = TypeID(prefix="x") |
| 164 | + dt = tid.created_at |
| 165 | + assert dt is not None |
| 166 | + _assert_utc_datetime(dt) |
| 167 | + |
| 168 | + |
| 169 | +def test_created_at_monotonic_increasing_for_multiple_new_ids(): |
| 170 | + # UUIDv7 embeds time; created_at should be non-decreasing across consecutive generations. |
| 171 | + # Note: UUIDv7 can generate multiple IDs within the same millisecond, so equality is allowed. |
| 172 | + t1 = TypeID(prefix="x").created_at |
| 173 | + t2 = TypeID(prefix="x").created_at |
| 174 | + t3 = TypeID(prefix="x").created_at |
| 175 | + |
| 176 | + assert t1 is not None and t2 is not None and t3 is not None |
| 177 | + assert t1 <= t2 <= t3 |
| 178 | + |
| 179 | + |
| 180 | +def test_created_at_does_not_crash_if_uuid_object_is_unexpected(monkeypatch): |
| 181 | + # If TypeID.uuid returns something odd that breaks version/int access, |
| 182 | + # created_at should return None (safe behavior). |
| 183 | + class WeirdUUID: |
| 184 | + @property |
| 185 | + def version(self): |
| 186 | + raise RuntimeError("nope") |
| 187 | + |
| 188 | + @property |
| 189 | + def int(self): |
| 190 | + raise RuntimeError("nope") |
| 191 | + |
| 192 | + tid = TypeID(prefix="x", suffix="00000000000000000000000000") |
| 193 | + |
| 194 | + # monkeypatch instance attribute/property access |
| 195 | + monkeypatch.setattr(type(tid), "uuid", property(lambda self: WeirdUUID())) |
| 196 | + |
| 197 | + assert tid.created_at is None |
| 198 | + |
| 199 | + |
| 200 | +def _assert_utc_datetime(dt: datetime) -> None: |
| 201 | + assert isinstance(dt, datetime) |
| 202 | + assert dt.tzinfo is timezone.utc |
| 203 | + # must be timezone-aware and normalized to UTC |
| 204 | + assert dt.utcoffset() == timezone.utc.utcoffset(dt) |
0 commit comments