feat: retention days limit and clone name templating and useful descr.
This commit is contained in:
@ -52,5 +52,4 @@ def test_analyze_dump_finds_and_clones_fixture(tmp_path: Path) -> None:
|
||||
|
||||
assert result.returncode == 0
|
||||
assert "Local clone payload passed validation." in result.stdout
|
||||
assert "GCClone 2026-06-16 Coach Ride" in result.stdout
|
||||
|
||||
assert "Coach Ride June 16, 2026 (gcclone)" in result.stdout
|
||||
|
||||
@ -2,7 +2,11 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from garmin_coach_clone.config import DEFAULT_FIXED_TIMES, load_settings
|
||||
from garmin_coach_clone.config import (
|
||||
DEFAULT_CLONE_NAME_TEMPLATE,
|
||||
DEFAULT_FIXED_TIMES,
|
||||
load_settings,
|
||||
)
|
||||
from garmin_coach_clone.db import Database
|
||||
from garmin_coach_clone.repository import Repository, ScheduleConfig, validate_schedule_config
|
||||
|
||||
@ -17,6 +21,7 @@ def test_schedule_restore_defaults(tmp_path, monkeypatch) -> None:
|
||||
restored = repo.restore_default_schedule()
|
||||
|
||||
assert restored.fixed_times == DEFAULT_FIXED_TIMES
|
||||
assert restored.clone_name_template == DEFAULT_CLONE_NAME_TEMPLATE
|
||||
assert repo.schedule_config().active_window == "05:00-22:00"
|
||||
|
||||
|
||||
@ -31,3 +36,18 @@ def test_schedule_validation_rejects_bad_window() -> None:
|
||||
days_ahead=1,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("template", ["", "{type} {date}", "{unknown} ({clone})"])
|
||||
def test_schedule_validation_rejects_invalid_clone_name_template(template: str) -> None:
|
||||
with pytest.raises(ValueError, match="clone name template|unknown clone"):
|
||||
validate_schedule_config(
|
||||
ScheduleConfig(
|
||||
enabled=True,
|
||||
interval_minutes=30,
|
||||
active_window="05:00-22:00",
|
||||
fixed_times=["05:15"],
|
||||
days_ahead=1,
|
||||
clone_name_template=template,
|
||||
)
|
||||
)
|
||||
|
||||
@ -397,6 +397,7 @@ def test_replace_changed_unschedules_matching_calendar_entries(
|
||||
|
||||
def test_sync_deletes_generated_clones_older_than_retention(tmp_path, monkeypatch) -> None:
|
||||
monkeypatch.setattr(sync_service, "_today", lambda settings: date(2026, 6, 16))
|
||||
monkeypatch.setenv("DELETE_OLD_CLONES", "true")
|
||||
source = _source("Sprint")
|
||||
service, _repo, garmin = _service(tmp_path, monkeypatch, source)
|
||||
old_name = "GCClone 2026-06-10 Sprint"
|
||||
|
||||
@ -7,15 +7,17 @@ from garmin_coach_clone.workouts import (
|
||||
calendar_entry_date,
|
||||
calendar_entry_id,
|
||||
calendar_entry_name,
|
||||
clone_workout_description,
|
||||
clone_workout_name,
|
||||
clone_workout_payload,
|
||||
estimate_duration,
|
||||
existing_clone_names,
|
||||
find_generated_calendar_entry,
|
||||
find_generated_workout,
|
||||
generated_clone_date,
|
||||
generated_calendar_entries,
|
||||
generated_workouts_older_than,
|
||||
generated_clone_date,
|
||||
generated_workouts,
|
||||
generated_workouts_older_than,
|
||||
validate_workout_payload,
|
||||
workout_steps_equal,
|
||||
)
|
||||
@ -38,13 +40,32 @@ def test_clone_payload_strips_ids_and_sets_prefix() -> None:
|
||||
|
||||
cloned = clone_workout_payload(source, date(2026, 6, 16), "GCClone")
|
||||
|
||||
assert cloned["workoutName"] == "GCClone 2026-06-16 Coach Original"
|
||||
assert cloned["workoutName"] == "Coach Original June 16, 2026 (gcclone)"
|
||||
assert "workoutId" not in cloned
|
||||
assert "ownerId" not in cloned
|
||||
assert "stepId" not in cloned["workoutSegments"][0]["workoutSteps"][0]
|
||||
assert validate_workout_payload(cloned) == []
|
||||
|
||||
|
||||
def test_clone_title_and_description_use_source_details() -> None:
|
||||
source = build_dummy_cycling_workout("Tempo")
|
||||
source["description"] = "3x10:00@180W"
|
||||
steps = source["workoutSegments"][0]["workoutSteps"]
|
||||
steps[0]["targetType"] = {"workoutTargetTypeKey": "power.zone"}
|
||||
steps[0]["targetValueOne"] = 98
|
||||
steps[0]["targetValueTwo"] = 142
|
||||
|
||||
assert clone_workout_name(
|
||||
"Tempo", date(2026, 7, 15), "GCClone", "{type} {date} ({clone})"
|
||||
) == "Tempo July 15, 2026 (gcclone)"
|
||||
assert clone_workout_description(source) == (
|
||||
"3x10:00@180W\n"
|
||||
"Intervals: Warm up 5:00 @ 98–142 W | 1× (Interval 2:00 | Recover 2:00) | "
|
||||
"Cool down 5:00\n"
|
||||
"GCClone — cloned from Garmin Coach; completing it may not update the Coach plan."
|
||||
)
|
||||
|
||||
|
||||
def test_workout_steps_equal_ignores_ids_but_compares_steps() -> None:
|
||||
left = build_dummy_cycling_workout("Left")
|
||||
right = build_dummy_cycling_workout("Right")
|
||||
|
||||
Reference in New Issue
Block a user