mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 21:27:13 +01:00
Some checks are pending
pre-commit / pre-commit (push) Waiting to run
Tests / test (3.10) (push) Waiting to run
Tests / test (3.11) (push) Waiting to run
Tests / test (3.12) (push) Waiting to run
Tests / lock-popup-safety (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
88 lines
3.3 KiB
Python
88 lines
3.3 KiB
Python
"""Cross-language fixture test for the unified workout-duration gate.
|
|
|
|
The Dart app mirrors these constants in ``lib/models/manual_workout.dart``.
|
|
Each language's own round-trip test passes happily while the two sides
|
|
disagree, so the only thing that catches a drift is a shared literal both
|
|
read -- ``fixtures/duration_threshold.json``. The Dart twin of this file is
|
|
``test/models/duration_threshold_fixture_test.dart``; they must stay in step.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from screen_locker._constants import (
|
|
MIN_WORKOUT_DURATION_MINUTES,
|
|
WORKOUT_DURATION_ACCEPT_MINUTES,
|
|
WORKOUT_DURATION_LEEWAY_MINUTES,
|
|
)
|
|
from screen_locker._manual_workout import ManualWorkoutDraft, validate_manual_workout
|
|
|
|
FIXTURE = Path(__file__).parent / "fixtures" / "duration_threshold.json"
|
|
|
|
|
|
def _fixture() -> dict[str, object]:
|
|
"""Load the shared cross-language threshold fixture."""
|
|
return json.loads(FIXTURE.read_text(encoding="utf-8"))
|
|
|
|
|
|
def _draft(duration_minutes: int) -> ManualWorkoutDraft:
|
|
"""Build an otherwise-valid draft of exactly ``duration_minutes``."""
|
|
end_h, end_m = divmod(12 * 60 + duration_minutes, 60)
|
|
return ManualWorkoutDraft(
|
|
sport="other",
|
|
start_time="12:00",
|
|
end_time=f"{end_h:02d}:{end_m:02d}",
|
|
location_name="Home",
|
|
transport_method="From bed",
|
|
cost="0",
|
|
rpe=3,
|
|
went_well="Everything went smoothly today, no issues at all",
|
|
to_improve="Dumbbell bench press needs assistance exercises",
|
|
overall_feeling="Felt strong throughout the whole session today",
|
|
reservation_phone="none",
|
|
techniques_practiced="FBW",
|
|
warm_up_minutes="none",
|
|
pain_or_injury="none",
|
|
activity_type_other="Weightlifting",
|
|
activity_details="Dumbbell Lunge, Press, Row and Dumbbell Curl at home",
|
|
equipment="Dumbbells",
|
|
)
|
|
|
|
|
|
def test_constants_match_shared_fixture() -> None:
|
|
"""The Python constants equal the shared literal the Dart side also reads."""
|
|
data = _fixture()
|
|
assert data["advertised_minutes"] == MIN_WORKOUT_DURATION_MINUTES
|
|
assert data["leeway_minutes"] == WORKOUT_DURATION_LEEWAY_MINUTES
|
|
assert data["accept_minutes"] == WORKOUT_DURATION_ACCEPT_MINUTES
|
|
|
|
|
|
def test_accept_bar_is_derived_not_hardcoded() -> None:
|
|
"""The two bars cannot drift: the accept bar is advertised minus leeway."""
|
|
assert (
|
|
WORKOUT_DURATION_ACCEPT_MINUTES
|
|
== MIN_WORKOUT_DURATION_MINUTES - WORKOUT_DURATION_LEEWAY_MINUTES
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("case", _fixture()["cases"])
|
|
def test_boundary_cases_from_fixture(case: dict[str, object]) -> None:
|
|
"""Every shared boundary case decides the same way on the Python side."""
|
|
error = validate_manual_workout(_draft(int(case["duration_minutes"])))
|
|
assert (error is None) is case["accepted"], (
|
|
f"{case['duration_minutes']} min should be "
|
|
f"{'accepted' if case['accepted'] else 'rejected'}, got {error!r}"
|
|
)
|
|
|
|
|
|
def test_rejection_message_advertises_40_never_the_real_cutoff() -> None:
|
|
"""The hidden accept bar must never reach the user's eyes."""
|
|
error = validate_manual_workout(_draft(10))
|
|
assert error is not None
|
|
assert str(MIN_WORKOUT_DURATION_MINUTES) in error
|
|
assert str(WORKOUT_DURATION_ACCEPT_MINUTES) not in error
|