75 lines
2.3 KiB
Python
75 lines
2.3 KiB
Python
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
from app.analytics import analyse, enrich, running_cost
|
|
|
|
|
|
def run(grade=0):
|
|
return SimpleNamespace(
|
|
sport="running",
|
|
distance_m=600,
|
|
samples=[
|
|
{
|
|
"distance": i * 3,
|
|
"time": i,
|
|
"elevation": 100 + i * 3 * grade,
|
|
"speed": 3,
|
|
"heart_rate": 150,
|
|
"cadence": 170,
|
|
}
|
|
for i in range(201)
|
|
],
|
|
laps=[{"distance": 301}, {"distance": 299}],
|
|
)
|
|
|
|
|
|
def test_flat_gap_and_laps_use_distance_weighted_time():
|
|
result = analyse(run())
|
|
assert result["summary"]["gap"] == pytest.approx(1000 / 3)
|
|
assert result["summary"]["gap_coverage"] == 100
|
|
assert [lap["gap"] for lap in result["laps"]] == pytest.approx([1000 / 3] * 2)
|
|
assert sum(lap["gap_time"] for lap in result["laps"]) == pytest.approx(200)
|
|
assert result["terrain"][1]["heart_rate"] == 150
|
|
|
|
|
|
@pytest.mark.parametrize("grade", [-0.1, 0.1])
|
|
def test_slope_adjusts_pace_using_cost_ratio(grade):
|
|
activity = run(grade)
|
|
row = enrich(activity.samples)[100]
|
|
assert row["grade"] == pytest.approx(grade * 100)
|
|
assert row["gap"] == pytest.approx(1000 / 3 * 3.6 / running_cost(grade))
|
|
gap = analyse(activity)["summary"]["gap"]
|
|
assert (gap < 1000 / 3) if grade > 0 else (gap > 1000 / 3)
|
|
|
|
|
|
def test_missing_data_and_nonrunning_do_not_invent_gap():
|
|
activity = run()
|
|
for row in activity.samples:
|
|
row["elevation"] = None
|
|
assert analyse(activity)["summary"]["gap"] is None
|
|
activity = run()
|
|
activity.sport = "cycling"
|
|
assert analyse(activity)["summary"]["gap"] is None
|
|
activity = run()
|
|
for row in activity.samples:
|
|
row["time"] = None
|
|
assert analyse(activity)["summary"]["gap"] is None
|
|
|
|
|
|
def test_recording_gap_excluded_from_time_and_distance():
|
|
activity = run()
|
|
for row in activity.samples[100:]:
|
|
row["time"] += 100
|
|
result = analyse(activity)
|
|
assert result["summary"]["gap"] == pytest.approx(1000 / 3)
|
|
assert result["summary"]["gap_coverage"] == pytest.approx(99.5)
|
|
|
|
|
|
def test_extreme_slopes_and_stationary_records_have_no_gap():
|
|
assert analyse(run(0.5))["summary"]["gap"] is None
|
|
activity = run()
|
|
for row in activity.samples:
|
|
row["distance"] = 0
|
|
assert analyse(activity)["summary"]["gap"] is None
|