Spaces:
Running on Zero
Running on Zero
File size: 3,621 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 96 97 98 99 100 101 102 103 104 | """Tests for formscout/types.py — contract validation."""
import pytest
from formscout.types import (
IngestResult, SegmentResult, Pose2DResult, Body3DResult,
MovementResult, BiomechFeatures, ScoreResult, RetrievalResult,
JudgeResult, ReportResult, PipelineState,
)
class TestIngestResult:
def test_frozen(self):
r = IngestResult(frames=[], fps=30.0, duration=2.0, n_people=1, width=1920, height=1080)
with pytest.raises(Exception):
r.fps = 60.0
def test_defaults(self):
r = IngestResult(frames=[], fps=30.0, duration=0.0, n_people=0, width=0, height=0)
assert r.confidence == 1.0
assert r.notes == ""
class TestMovementResult:
def test_valid_tests(self):
r = MovementResult(test_name="deep_squat", side="na", confidence=0.9)
assert r.test_name == "deep_squat"
def test_invalid_test_raises(self):
with pytest.raises(ValueError, match="test_name"):
MovementResult(test_name="jumping_jacks", side="na", confidence=0.5)
def test_invalid_side_raises(self):
with pytest.raises(ValueError, match="side"):
MovementResult(test_name="deep_squat", side="both", confidence=0.5)
class TestBiomechFeatures:
def test_valid_views(self):
f = BiomechFeatures(
test_name="deep_squat", view="2d", side="na",
angles={}, alignments={}, symmetry_delta=None, timing={},
confidence=0.8,
)
assert f.view == "2d"
def test_invalid_view_raises(self):
with pytest.raises(ValueError, match="view"):
BiomechFeatures(
test_name="deep_squat", view="4d", side="na",
angles={}, alignments={}, symmetry_delta=None, timing={},
confidence=0.8,
)
class TestScoreResult:
def test_valid_score(self):
r = ScoreResult(score=3, rationale="good", confidence=0.9)
assert r.score == 3
def test_invalid_score_raises(self):
with pytest.raises(ValueError):
ScoreResult(score=4, rationale="bad", confidence=0.9)
def test_score_minus_one_invalid_when_not_needs_human(self):
with pytest.raises(ValueError):
ScoreResult(score=-1, rationale="x", confidence=0.5)
class TestJudgeResult:
def test_needs_human_score_must_be_none(self):
with pytest.raises(ValueError):
JudgeResult(
score=2, rationale="pain", compensation_tags=[],
corrective_hint="", confidence=0.5, needs_human=True,
)
def test_needs_human_with_none_score(self):
r = JudgeResult(
score=None, rationale="pain observed", compensation_tags=[],
corrective_hint="", confidence=0.5, needs_human=True,
)
assert r.needs_human is True
assert r.score is None
def test_valid_score(self):
r = JudgeResult(
score=2, rationale="ok", compensation_tags=["heel_rise"],
corrective_hint="work on ankle mobility", confidence=0.85,
)
assert r.score == 2
class TestPipelineState:
def test_mutable(self):
s = PipelineState(video_path="/tmp/test.mp4")
s.ingest = IngestResult(frames=[], fps=30.0, duration=1.0, n_people=1, width=640, height=480)
assert s.ingest is not None
def test_defaults(self):
s = PipelineState(video_path="test.mp4")
assert s.ingest is None
assert s.errors == []
assert s.warnings == []
|