Make unified tests match the -k filter

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWZ9CKZsNxtD5Jr9bYD
This commit is contained in:
Krzysztof Rudnicki 2026-11-10 18:26:23 +01:00
parent 0a48b76d59
commit f528722e1f
5 changed files with 27 additions and 8 deletions

View File

@ -73,11 +73,11 @@ WORKOUT_DURATION_ACCEPT_MINUTES = (
)
RUNNERUP_PACKAGES = ("org.runnerup", "org.runnerup.free")
RUNNERUP_DB_SDCARD_TMP = "/sdcard/.runnerup_tmp_verification.db"
# A run qualifies on EITHER criterion — they are an OR, not an AND. A short
# but long-lasting run counts, and so does a fast 5 km that takes under the
# duration bar. Do not reinstate an AND here: it would reject exactly the
# slow-run case this pair exists to allow. The duration arm is the shared
# MIN_WORKOUT_DURATION_MINUTES above; only the distance arm is run-specific.
# A day's activity (run or walk alike) qualifies on EITHER criterion — they are
# an OR, not an AND. A short but long-lasting session counts, and so does a
# fast 5 km that takes under the duration bar. Do not reinstate an AND here:
# it would reject exactly the slow case this pair exists to allow. The
# duration arm is the shared MIN_WORKOUT_DURATION_MINUTES above (moving time).
MIN_RUN_DISTANCE_KM = 3.5 # inclusive: "as low as 3.5 km"
# GPS distance tracking undershoots on tight turns/tree cover/urban canyons;
# a run within 5% of the minimum is accepted rather than rejected on

View File

@ -4,8 +4,8 @@ Every other earner publishes its credits as HMAC-signed rows in a ledger that
``earned_time`` reads (``first_credit_at``, ``credit_units``). This is the
workout's: ``~/.local/share/workout_locker/ledger.json``, one row per
* workout credit slot in ``log.json`` -- RunnerUp (a run, or the day's walks
summed), StrongLifts (phone or PC session), manual, any lock-screen or
* workout credit slot in ``log.json`` -- RunnerUp (the day's runs and walks,
summed by one rule), StrongLifts (phone or PC session), manual, any lock-screen or
verify path -- appended by the one log write chokepoint
(``_log_mixin.write_signed_entry``), so no path can credit without it; and
* declared rest day -- appended when it is declared.

View File

@ -175,3 +175,21 @@ class TestActivityDay:
"""The shortfall names both ways to qualify."""
day: ActivityDay = activity_day([{"distance_m": 100.0, "moving_seconds": 60.0}])
assert activity_shortfall(day).endswith("need 3.5+ km or 30+ min moving")
class TestLapOnlyExport:
"""An export with laps but no trackpoints has no moving time to credit."""
def test_wall_clock_alone_credits_nothing(self, verifier: Verifier) -> None:
"""40 min on the lap clock, 1 km, no trackpoints: too short."""
body = (
'<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/'
'TrainingCenterDatabase/v2"><Activities><Activity Sport="Running">'
"<Id>2026-10-10T08:00</Id><Lap><TotalTimeSeconds>2400</TotalTimeSeconds>"
"<DistanceMeters>1000</DistanceMeters></Lap></Activity></Activities>"
"</TrainingCenterDatabase>"
)
drop(verifier.folder, "08-00-00", "_Running", body)
result = verify(verifier)
assert result is not None
assert result[0] == "too_short"

View File

@ -28,7 +28,8 @@ const double kRunningMaxSpeedMps = 25 / 3.6;
/// Speed cap above which a fix is a GPS jump, 8 km/h for a walk.
const double kWalkingMaxSpeedMps = 8 / 3.6;
/// The jump cap for [sport].
/// The jump cap for [sport]. Display only: the PC has no upper speed, so the
/// moving time shown here can be below what the PC credits, never above.
double maxSpeedMps(RunSport sport) => switch (sport) {
RunSport.running => kRunningMaxSpeedMps,
RunSport.walking => kWalkingMaxSpeedMps,