117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
"""时态快照测试。"""
|
||
|
||
from datetime import UTC, datetime
|
||
|
||
from app.modules.time_sense.duration import OfflineThresholds
|
||
from app.modules.time_sense.snapshot import (
|
||
AnniversaryRef,
|
||
LocationContext,
|
||
SnapshotInput,
|
||
compute_snapshot,
|
||
)
|
||
|
||
|
||
def _input(**overrides):
|
||
base = {
|
||
"now": datetime(2026, 7, 3, 2, 42, tzinfo=UTC),
|
||
"timezone": "Asia/Shanghai",
|
||
"location": LocationContext(timezone="Asia/Shanghai", city="上海"),
|
||
"anniversaries": [],
|
||
"acquaintance_anchor": datetime(2025, 9, 19, tzinfo=UTC),
|
||
"last_active_at": datetime(2026, 7, 3, 2, 0, tzinfo=UTC),
|
||
"home_timezone": "Asia/Shanghai",
|
||
"offline_thresholds": OfflineThresholds(),
|
||
}
|
||
base.update(overrides)
|
||
return SnapshotInput(**base)
|
||
|
||
|
||
def test_snapshot_basic_fields():
|
||
snap = compute_snapshot(_input())
|
||
assert snap.timezone == "Asia/Shanghai"
|
||
# 上海 UTC+8,02:42 UTC -> 10:42 本地
|
||
assert snap.local_hour == 10
|
||
assert snap.shichen in {"辰", "巳"} # 7-11 点区间
|
||
assert snap.day_period in {"上午"}
|
||
assert snap.weekday is not None
|
||
|
||
|
||
def test_snapshot_acquaintance_and_offline():
|
||
snap = compute_snapshot(_input())
|
||
assert snap.acquaintance.total_days > 280
|
||
assert snap.offline.band == "active"
|
||
|
||
|
||
def test_snapshot_home_tz_diff_zero():
|
||
snap = compute_snapshot(_input())
|
||
assert snap.home_tz_diff_minutes == 0
|
||
|
||
|
||
def test_snapshot_next_milestone_from_anniversary():
|
||
# 下一个相识周年:相识日 2025-09-19,到 2026-07-03 距下一周年(2026-09-19)约 78 天
|
||
anni = AnniversaryRef(
|
||
id="anniv_1",
|
||
name="相识纪念日",
|
||
calendar="solar",
|
||
date_iso="2025-09-19",
|
||
recurs_yearly=True,
|
||
kind="anniversary",
|
||
)
|
||
snap = compute_snapshot(_input(anniversaries=[anni]))
|
||
assert snap.next_milestone is not None
|
||
assert snap.next_milestone.name == "相识纪念日"
|
||
assert 70 < snap.next_milestone.days_until < 85
|
||
|
||
|
||
def test_snapshot_active_milestone_today():
|
||
# 相识日恰好今天(构造一个今日命中的纪念日)
|
||
today = datetime(2026, 7, 3, tzinfo=UTC)
|
||
|
||
anni = AnniversaryRef(
|
||
id="anniv_birthday",
|
||
name="小明生日",
|
||
calendar="solar",
|
||
date_iso="2026-07-03",
|
||
recurs_yearly=False,
|
||
kind="birthday",
|
||
)
|
||
snap = compute_snapshot(_input(anniversaries=[anni], acquaintance_anchor=today))
|
||
assert any(m.name == "小明生日" for m in snap.active_milestones)
|
||
assert snap.next_milestone is None or snap.next_milestone.name != "小明生日"
|
||
|
||
|
||
def test_snapshot_lunar_present():
|
||
snap = compute_snapshot(_input())
|
||
# 农历字段非空(lunar_python 可用时)
|
||
assert snap.lunar is not None
|
||
assert snap.lunar.year_ganzhi == "丙午"
|
||
|
||
|
||
def test_snapshot_2_29_anniversary_in_non_leap_year():
|
||
# 2/29 周年在非闰年不应崩溃,且应回退到 2/28 后能算出下一周年
|
||
anni = AnniversaryRef(
|
||
id="anniv_leap",
|
||
name="闰年相识",
|
||
calendar="solar",
|
||
date_iso="2024-02-29",
|
||
recurs_yearly=True,
|
||
kind="anniversary",
|
||
)
|
||
snap = compute_snapshot(_input(anniversaries=[anni]))
|
||
assert snap.next_milestone is not None
|
||
assert snap.next_milestone.name == "闰年相识"
|
||
|
||
|
||
def test_snapshot_recurring_milestone_today():
|
||
# recurs_yearly=True 且月日命中今天:应进入 active_milestones
|
||
anni = AnniversaryRef(
|
||
id="anniv_today",
|
||
name="今日周年",
|
||
calendar="solar",
|
||
date_iso="2026-07-03",
|
||
recurs_yearly=True,
|
||
kind="anniversary",
|
||
)
|
||
snap = compute_snapshot(_input(anniversaries=[anni]))
|
||
assert any(m.id == "anniv_today" for m in snap.active_milestones)
|