from datetime import date from app.models import ChartInput, DailyRecordInput, MetricValue, TaskInput from app.repository import ConflictError, JsonRepository def _task(repo): return repo.create_task(TaskInput.model_validate({ "name": "复盘任务", "metrics": [ {"name": "完成", "kind": "checkin", "period": "day"}, {"name": "数量", "kind": "quantity", "period": "day"}, ], })) def test_chart_crud_and_conflict(tmp_path): repo = JsonRepository(tmp_path) chart = repo.create_chart(ChartInput(title="趋势")) assert repo.list_charts()["items"][0]["chartId"] == chart["chartId"] updated = repo.update_chart(chart["chartId"], ChartInput(title="新趋势"), chart["version"]) assert updated["version"] == 2 try: repo.update_chart(chart["chartId"], ChartInput(title="冲突"), chart["version"]) except ConflictError: pass else: raise AssertionError("expected chart version conflict") assert repo.delete_chart(chart["chartId"])["deleted"] is True def test_chart_data_modes_and_continuous_points(tmp_path): repo = JsonRepository(tmp_path) task = _task(repo) checkin_id, quantity_id = [metric["metricId"] for metric in task["metrics"]] repo.upsert_daily(task["taskId"], date(2026, 8, 2), DailyRecordInput(values=[MetricValue(metricId=checkin_id, value=1), MetricValue(metricId=quantity_id, value=3)], note="完成")) repo.upsert_daily(task["taskId"], date(2026, 8, 4), DailyRecordInput(values=[MetricValue(metricId=quantity_id, value=2)])) done = repo.create_chart(ChartInput(title="完成数", days=7)) metric = repo.create_chart(ChartInput(title="数量", taskId=task["taskId"], metricId=quantity_id, days=7)) for result in (repo.chart_data(done["chartId"], date(2026, 8, 4)), repo.chart_data(metric["chartId"], date(2026, 8, 4))): assert len(result["points"]) == 7 assert [point["date"] for point in result["points"]] == sorted(point["date"] for point in result["points"]) done_points = {point["date"]: point["value"] for point in repo.chart_data(done["chartId"], date(2026, 8, 4))["points"]} metric_points = {point["date"]: point["value"] for point in repo.chart_data(metric["chartId"], date(2026, 8, 4))["points"]} assert done_points["2026-08-03"] == 0 and done_points["2026-08-04"] == 1 assert metric_points["2026-08-02"] == 3 and metric_points["2026-08-03"] == 0 def test_review_notes_skips_empty_and_resolves_deleted_task(tmp_path): repo = JsonRepository(tmp_path) task = _task(repo) repo.upsert_daily(task["taskId"], date(2026, 8, 1), DailyRecordInput(note="心得")) repo.upsert_daily(task["taskId"], date(2026, 8, 2), DailyRecordInput()) repo.soft_delete_task(task["taskId"], task["version"]) result = repo.review_notes(date(2026, 8, 1), date(2026, 8, 2)) assert [day["date"] for day in result["days"]] == ["2026-08-01"] assert result["days"][0]["records"][0]["taskName"] == "已删除任务" def test_export_import_charts(tmp_path): repo = JsonRepository(tmp_path) repo.create_chart(ChartInput(title="备份图表")) exported = repo.export_all() assert len(exported["charts"]) == 1 target = JsonRepository(tmp_path / "target") target.import_all(exported) assert target.stats()["chartCount"] == 1 legacy = {key: value for key, value in exported.items() if key != "charts"} target.import_all(legacy) assert target.stats()["chartCount"] == 0