"""报告生成测试""" from datetime import date, time, timedelta from pathlib import Path import pytest from src.vitals.core import database as db from src.vitals.core.models import Exercise, Meal, Sleep, Weight, UserConfig from src.vitals.core.report import ( generate_weekly_report, generate_monthly_report, render_weekly_report_terminal, render_weekly_report_markdown, render_weekly_report_html, export_report, ) @pytest.fixture def populated_db(): """填充测试数据""" today = date.today() # 添加用户配置 config = UserConfig( age=28, gender="male", height=175.0, weight=72.0, activity_level="moderate", goal="lose", ) db.save_config(config) # 添加本周数据 for i in range(7): day = today - timedelta(days=today.weekday()) + timedelta(days=i) # 运动 if i % 2 == 0: db.add_exercise(Exercise( date=day, type="跑步", duration=30, calories=240, )) # 饮食 db.add_meal(Meal( date=day, meal_type="午餐", description="米饭+鸡肉", calories=500, )) # 睡眠 db.add_sleep(Sleep( date=day, duration=7.0 + i * 0.1, quality=3 + (i % 3), )) # 体重 db.add_weight(Weight( date=day, weight_kg=72.0 - i * 0.1, )) return today class TestGenerateWeeklyReport: """周报生成测试""" def test_generate_report(self, populated_db): """测试生成周报""" report = generate_weekly_report() assert report is not None assert report.exercise_count > 0 assert report.exercise_duration > 0 def test_report_date_range(self, populated_db): """测试日期范围""" report = generate_weekly_report() # 本周应该是周一到周日 assert report.end_date - report.start_date == timedelta(days=6) assert report.start_date.weekday() == 0 # 周一 def test_report_exercise_stats(self, populated_db): """测试运动统计""" report = generate_weekly_report() assert report.exercise_count > 0 assert report.exercise_duration > 0 assert report.exercise_calories > 0 assert "跑步" in report.exercise_types def test_report_sleep_stats(self, populated_db): """测试睡眠统计""" report = generate_weekly_report() assert report.avg_sleep_duration > 0 assert 1 <= report.avg_sleep_quality <= 5 def test_report_weight_stats(self, populated_db): """测试体重统计""" report = generate_weekly_report() assert report.weight_start is not None assert report.weight_end is not None assert report.weight_change is not None def test_report_daily_stats(self, populated_db): """测试每日统计""" report = generate_weekly_report() assert len(report.daily_stats) == 7 for stat in report.daily_stats: assert stat.weekday in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] def test_report_with_custom_date(self, populated_db): """测试指定日期""" report = generate_weekly_report(date(2026, 1, 15)) # 2026-01-15 是周四, 那周的周一是 01-12 assert report.start_date == date(2026, 1, 12) assert report.end_date == date(2026, 1, 18) class TestGenerateMonthlyReport: """月报生成测试""" def test_generate_report(self, populated_db): """测试生成月报""" report = generate_monthly_report() assert report is not None assert report.year > 0 assert 1 <= report.month <= 12 def test_report_date_range(self, populated_db): """测试日期范围""" report = generate_monthly_report(2026, 1) assert report.start_date == date(2026, 1, 1) assert report.end_date == date(2026, 1, 31) def test_report_exercise_stats(self, populated_db): """测试运动统计""" report = generate_monthly_report() assert report.exercise_count >= 0 assert report.exercise_days >= 0 def test_report_weekly_summaries(self, populated_db): """测试周汇总""" report = generate_monthly_report() assert len(report.weekly_summaries) > 0 for week in report.weekly_summaries: assert "week" in week assert "exercise_duration" in week def test_report_with_custom_month(self): """测试指定月份""" report = generate_monthly_report(2025, 6) assert report.year == 2025 assert report.month == 6 class TestRenderWeeklyReportTerminal: """终端渲染测试""" def test_render_contains_sections(self, populated_db): """测试包含各部分""" report = generate_weekly_report() output = render_weekly_report_terminal(report) assert "运动" in output assert "睡眠" in output assert "饮食" in output assert "体重" in output assert "每日明细" in output def test_render_contains_stats(self, populated_db): """测试包含统计数据""" report = generate_weekly_report() output = render_weekly_report_terminal(report) assert "分钟" in output assert "卡" in output class TestRenderWeeklyReportMarkdown: """Markdown 渲染测试""" def test_render_is_valid_markdown(self, populated_db): """测试是有效的 Markdown""" report = generate_weekly_report() output = render_weekly_report_markdown(report) assert output.startswith("# ") assert "## " in output assert "| " in output # 表格 def test_render_contains_sections(self, populated_db): """测试包含各部分""" report = generate_weekly_report() output = render_weekly_report_markdown(report) assert "## 运动" in output assert "## 睡眠" in output assert "## 饮食" in output assert "## 体重" in output class TestRenderWeeklyReportHtml: """HTML 渲染测试""" def test_render_is_valid_html(self, populated_db): """测试是有效的 HTML""" report = generate_weekly_report() output = render_weekly_report_html(report) assert "" in output assert "" in output def test_render_contains_styles(self, populated_db): """测试包含样式""" report = generate_weekly_report() output = render_weekly_report_html(report) assert "" in output def test_render_contains_data(self, populated_db): """测试包含数据""" report = generate_weekly_report() output = render_weekly_report_html(report) assert "运动" in output assert "睡眠" in output class TestExportReport: """报告导出测试""" def test_export_markdown(self, populated_db, tmp_path): """测试导出 Markdown""" report = generate_weekly_report() output_path = tmp_path / "report.md" result = export_report(report, output_path) assert result is True assert output_path.exists() content = output_path.read_text() assert "# " in content def test_export_html(self, populated_db, tmp_path): """测试导出 HTML""" report = generate_weekly_report() output_path = tmp_path / "report.html" result = export_report(report, output_path) assert result is True assert output_path.exists() content = output_path.read_text() assert "" in content def test_export_unsupported_format(self, populated_db, tmp_path): """测试不支持的格式""" report = generate_weekly_report() output_path = tmp_path / "report.xyz" result = export_report(report, output_path) assert result is False class TestEmptyData: """空数据测试""" def test_weekly_report_empty(self): """测试空数据周报""" report = generate_weekly_report() assert report.exercise_count == 0 assert report.avg_sleep_duration == 0 assert report.weight_start is None def test_monthly_report_empty(self): """测试空数据月报""" report = generate_monthly_report() assert report.exercise_count == 0 assert report.avg_sleep_duration == 0 def test_render_empty_report(self): """测试渲染空报告""" report = generate_weekly_report() output = render_weekly_report_terminal(report) assert "暂无记录" in output or "0" in output