初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,104 @@
|
||||
"""时间深度与离线档位测试。"""
|
||||
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from app.modules.time_sense.duration import (
|
||||
OfflineThresholds,
|
||||
classify_offline_band,
|
||||
compute_acquaintance_duration,
|
||||
format_duration_cn,
|
||||
)
|
||||
|
||||
|
||||
def test_acquaintance_duration_zero_days():
|
||||
anchor = datetime(2026, 7, 3, tzinfo=UTC)
|
||||
now = anchor
|
||||
d = compute_acquaintance_duration(anchor, now)
|
||||
assert d.total_days == 0
|
||||
assert "今天" in d.natural_language or "刚" in d.natural_language
|
||||
|
||||
|
||||
def test_acquaintance_duration_287_days():
|
||||
anchor = datetime(2026, 7, 3, tzinfo=UTC) - timedelta(days=287)
|
||||
now = datetime(2026, 7, 3, tzinfo=UTC)
|
||||
d = compute_acquaintance_duration(anchor, now)
|
||||
assert d.total_days == 287
|
||||
assert d.years == 0
|
||||
assert d.months == 9
|
||||
assert d.days == 17 # 287 % 30 = 17(按 30 天/月近似)
|
||||
assert "287" in d.natural_language
|
||||
|
||||
|
||||
def test_acquaintance_duration_one_year():
|
||||
anchor = datetime(2025, 7, 3, tzinfo=UTC)
|
||||
now = datetime(2026, 7, 3, tzinfo=UTC)
|
||||
d = compute_acquaintance_duration(anchor, now)
|
||||
assert d.total_days == 365
|
||||
assert d.years == 1
|
||||
|
||||
|
||||
def test_format_duration_cn_100_days():
|
||||
# 100 天 = 3 个月 10 天(按 30 天/月近似),实现走月日分支
|
||||
assert format_duration_cn(100) == "3 个月 10 天(100 天)"
|
||||
|
||||
|
||||
def test_format_duration_cn_365_days():
|
||||
text = format_duration_cn(365)
|
||||
assert "1 年" in text
|
||||
|
||||
|
||||
def test_classify_offline_band_active():
|
||||
now = datetime(2026, 7, 3, 12, 0, tzinfo=UTC)
|
||||
last = now - timedelta(minutes=30)
|
||||
t = OfflineThresholds()
|
||||
result = classify_offline_band(last, now, t)
|
||||
assert result.band == "active"
|
||||
assert result.minutes == 30
|
||||
|
||||
|
||||
def test_classify_offline_band_short_absence():
|
||||
now = datetime(2026, 7, 3, 12, 0, tzinfo=UTC)
|
||||
last = now - timedelta(hours=5)
|
||||
result = classify_offline_band(last, now, OfflineThresholds())
|
||||
assert result.band == "short_absence"
|
||||
|
||||
|
||||
def test_classify_offline_band_reunion_impact():
|
||||
now = datetime(2026, 7, 3, 12, 0, tzinfo=UTC)
|
||||
last = now - timedelta(days=5)
|
||||
result = classify_offline_band(last, now, OfflineThresholds())
|
||||
assert result.band == "reunion_impact"
|
||||
assert result.reunion_intensity > 0.5
|
||||
|
||||
|
||||
def test_classify_offline_boundary_59min_is_active():
|
||||
now = datetime(2026, 7, 3, 12, 0, tzinfo=UTC)
|
||||
last = now - timedelta(minutes=59)
|
||||
assert classify_offline_band(last, now, OfflineThresholds()).band == "active"
|
||||
|
||||
|
||||
def test_classify_offline_boundary_60min_is_short_absence():
|
||||
now = datetime(2026, 7, 3, 12, 0, tzinfo=UTC)
|
||||
last = now - timedelta(minutes=60)
|
||||
assert classify_offline_band(last, now, OfflineThresholds()).band == "short_absence"
|
||||
|
||||
|
||||
def test_offline_thresholds_violates_monotonicity():
|
||||
with pytest.raises(ValidationError):
|
||||
OfflineThresholds(active_minutes=100, short_absence_minutes=50)
|
||||
|
||||
|
||||
def test_reunion_intensity_clamped_05_to_1():
|
||||
now = datetime(2026, 7, 3, 12, 0, tzinfo=UTC)
|
||||
# 刚过 reunion_impact 阈值(4320 分钟 + 1 分钟)
|
||||
last = now - timedelta(minutes=4321)
|
||||
intensity = classify_offline_band(last, now, OfflineThresholds()).reunion_intensity
|
||||
assert 0.5 <= intensity <= 1.0
|
||||
|
||||
# 超大间隔:30 天 = 43200 分钟,应趋近 1.0
|
||||
last_far = now - timedelta(minutes=43200)
|
||||
intensity_far = classify_offline_band(last_far, now, OfflineThresholds()).reunion_intensity
|
||||
assert intensity_far > 0.9
|
||||
Reference in new issue
Block a user