Spaces:
Running on Zero
Running on Zero
File size: 3,987 Bytes
4948993 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | """Tests for the FMS session accumulator — no GPU, no model downloads."""
import numpy as np
from formscout.types import (
IngestResult, Pose2DResult, BiomechFeatures, ScoreResult, JudgeResult,
MovementResult, SessionEntry,
)
def test_session_entry_holds_typed_objects():
movement = MovementResult(test_name="deep_squat", side="na", confidence=1.0)
features = BiomechFeatures(
test_name="deep_squat", view="2d", side="na",
angles={"left_knee_flexion_deg": 95.0}, alignments={"knees_tracking_over_feet": True},
symmetry_delta=None, timing={"deepest_frame": 2}, confidence=0.9,
)
rubric = ScoreResult(score=2, rationale="ok", confidence=0.8)
judge = JudgeResult(score=2, rationale="ok", compensation_tags=["heels elevated"],
corrective_hint="ankle mobility", confidence=0.85)
entry = SessionEntry(
test_name="deep_squat", side="na", score=2, needs_human=False,
rationale="ok", compensation_tags=["heels elevated"], corrective_hint="ankle mobility",
measurements={"left_knee_flexion_deg": 95.0}, confidence=0.85, view="2d",
keyframe_path=None, movement=movement, features=features,
rubric_score=rubric, judge=judge,
)
assert entry.score == 2
assert entry.movement.test_name == "deep_squat"
assert entry.rubric_score.score == 2
assert entry.judge.compensation_tags == ["heels elevated"]
def _ingest(n=5, h=480, w=640):
frames = [np.zeros((h, w, 3), dtype=np.uint8) for _ in range(n)]
return IngestResult(frames=frames, fps=30.0, duration=n / 30.0, n_people=1, width=w, height=h)
def _pose(n=5):
kps = []
for i in range(n):
kps.append({j: {"x": float(50 + j * 25), "y": float(80 + j * 18), "conf": 0.9}
for j in range(17)})
return Pose2DResult(keypoints=kps, fps=30.0, confidence=0.9)
def _features(test_name="deep_squat", side="na", frame_key="deepest_frame"):
return BiomechFeatures(
test_name=test_name, view="2d", side=side,
angles={"left_knee_flexion_deg": 95.0},
alignments={"knees_tracking_over_feet": False},
symmetry_delta=None, timing={frame_key: 2}, confidence=0.9,
)
def _judge(score=2, needs_human=False):
return JudgeResult(
score=None if needs_human else score, rationale="r",
compensation_tags=["heels elevated"], corrective_hint="ankle mobility",
confidence=0.85, needs_human=needs_human,
)
def test_add_analysis_appends_entry_and_writes_files():
import os
from formscout import session as S
sess = S.new_session()
entry = S.add_analysis(sess, ingest=_ingest(), pose2d=_pose(),
features=_features(), judge=_judge(), test_name="deep_squat", side="na")
assert len(sess.entries) == 1
assert entry.score == 2
assert os.path.exists(os.path.join(sess.session_dir, "session.json"))
assert os.path.exists(os.path.join(sess.session_dir, "analysis.md"))
# key-frame still written (deepest_frame=2 is valid)
assert entry.keyframe_path and os.path.exists(entry.keyframe_path)
def test_finish_composite_null_when_needs_human():
from formscout import session as S
sess = S.new_session()
S.add_analysis(sess, ingest=_ingest(), pose2d=_pose(), features=_features(),
judge=_judge(score=3), test_name="deep_squat", side="na")
S.add_analysis(sess, ingest=_ingest(), pose2d=_pose(),
features=_features("trunk_stability_pushup", frame_key="max_sag_frame"),
judge=_judge(needs_human=True), test_name="trunk_stability_pushup", side="na")
report, pdf_path = S.finish_session(sess)
assert report is not None
assert report.composite is None # one test needs_human
def test_finish_empty_session_returns_none():
from formscout import session as S
sess = S.new_session()
report, pdf_path = S.finish_session(sess)
assert report is None and pdf_path is None
|