diff --git a/services/analysis-engine/tests/test_priority.py b/services/analysis-engine/tests/test_priority.py index dfe135e0..d331c35b 100644 --- a/services/analysis-engine/tests/test_priority.py +++ b/services/analysis-engine/tests/test_priority.py @@ -2,83 +2,101 @@ from typing import Any, cast -from bandscope_analysis.roles.model import RehearsalPriority +from bandscope_analysis.roles.model import RehearsalPriority, RehearsalRole from bandscope_analysis.roles.priority import calculate_rehearsal_priority -def test_calculate_priority_low_confidence() -> None: - """Test that low confidence always yields HIGH priority.""" +def _create_mock_role(**kwargs: Any) -> RehearsalRole: + """Helper to create a well-formed RehearsalRole mock.""" role = { - "confidence": {"level": "low"}, - "overlapWarnings": [], - "manualOverrides": [], + "id": "mock_id", + "name": "mock_name", + "roleType": "instrument", + "harmony": {"chord": "C", "functionLabel": "I", "source": "model"}, + "cue": {"kind": "count", "value": "1234"}, + "range": {"lowestNote": "C4", "highestNote": "G4"}, + "confidence": {"level": "high", "source": "model", "notes": ""}, + "rehearsalPriority": RehearsalPriority.LOW, + "simplification": "", "setupNote": "", + "manualOverrides": [], + "overlapWarnings": [], } - assert calculate_rehearsal_priority(cast(Any, role)) == RehearsalPriority.HIGH + role.update(kwargs) + return cast(RehearsalRole, role) + + +def test_calculate_priority_low_confidence() -> None: + """Test that low confidence always yields HIGH priority.""" + role = _create_mock_role(confidence={"level": "low", "source": "model", "notes": ""}) + assert calculate_rehearsal_priority(role) == RehearsalPriority.HIGH def test_calculate_priority_with_overlap() -> None: """Test that having overlap warnings yields HIGH priority.""" - role = { - "confidence": {"level": "high"}, - "overlapWarnings": ["Melodic overlap"], - "manualOverrides": [], - "setupNote": "", - } - assert calculate_rehearsal_priority(cast(Any, role)) == RehearsalPriority.HIGH + role = _create_mock_role(overlapWarnings=["Melodic overlap"]) + assert calculate_rehearsal_priority(role) == RehearsalPriority.HIGH def test_calculate_priority_medium_confidence() -> None: """Test that medium confidence yields MEDIUM priority without overlaps.""" - role = { - "confidence": {"level": "medium"}, - "overlapWarnings": [], - "manualOverrides": [], - "setupNote": "", - } - assert calculate_rehearsal_priority(cast(Any, role)) == RehearsalPriority.MEDIUM + role = _create_mock_role(confidence={"level": "medium", "source": "model", "notes": ""}) + assert calculate_rehearsal_priority(role) == RehearsalPriority.MEDIUM def test_calculate_priority_with_setup_note() -> None: """Test that having setup notes yields MEDIUM priority even if confidence is high.""" - role = { - "confidence": {"level": "high"}, - "overlapWarnings": [], - "manualOverrides": [], - "setupNote": "Switch to distortion", - } - assert calculate_rehearsal_priority(cast(Any, role)) == RehearsalPriority.MEDIUM + role = _create_mock_role(setupNote="Switch to distortion") + assert calculate_rehearsal_priority(role) == RehearsalPriority.MEDIUM def test_calculate_priority_with_simplification() -> None: """Test that simplification yields MEDIUM priority even if confidence is high.""" - role = { - "confidence": {"level": "high"}, - "overlapWarnings": [], - "manualOverrides": [], - "setupNote": "", - "simplification": "Simplify to quarter notes", - } - assert calculate_rehearsal_priority(cast(Any, role)) == RehearsalPriority.MEDIUM + role = _create_mock_role(simplification="Simplify to quarter notes") + assert calculate_rehearsal_priority(role) == RehearsalPriority.MEDIUM def test_calculate_priority_low() -> None: """Test that high confidence with no warnings or notes yields LOW priority.""" - role = { - "confidence": {"level": "high"}, - "overlapWarnings": [], - "manualOverrides": [], - "setupNote": "", - } - assert calculate_rehearsal_priority(cast(Any, role)) == RehearsalPriority.LOW + role = _create_mock_role() + assert calculate_rehearsal_priority(role) == RehearsalPriority.LOW def test_calculate_priority_with_manual_override() -> None: """Test that manual overrides yield HIGH priority.""" - role = { - "confidence": {"level": "high"}, - "overlapWarnings": [], - "manualOverrides": ["User corrected chord"], - "setupNote": "", - } - assert calculate_rehearsal_priority(cast(Any, role)) == RehearsalPriority.HIGH + role = _create_mock_role(manualOverrides=[{"field": "harmony", "value": {}, "source": "user"}]) + assert calculate_rehearsal_priority(role) == RehearsalPriority.HIGH + + +def test_calculate_priority_empty_role() -> None: + """Test that an empty role dict defaults to LOW priority safely.""" + # Although a true RehearsalRole has all fields, we want to ensure + # our heuristic handles partial dicts or missing keys gracefully. + role = {} + assert calculate_rehearsal_priority(cast(RehearsalRole, role)) == RehearsalPriority.LOW + + +def test_calculate_priority_missing_confidence_level() -> None: + """Test that a missing confidence level defaults to HIGH/LOW appropriately.""" + role = _create_mock_role(confidence={"source": "model", "notes": ""}) + assert calculate_rehearsal_priority(role) == RehearsalPriority.LOW + + +def test_calculate_priority_multiple_medium_conditions() -> None: + """Test that multiple medium conditions still yield MEDIUM.""" + role = _create_mock_role( + confidence={"level": "medium", "source": "model", "notes": ""}, + setupNote="Some note", + simplification="Some simplification", + ) + assert calculate_rehearsal_priority(role) == RehearsalPriority.MEDIUM + + +def test_calculate_priority_high_overrides_medium() -> None: + """Test that high priority conditions override medium priority ones.""" + role = _create_mock_role( + confidence={"level": "medium", "source": "model", "notes": ""}, + overlapWarnings=["Warning"], + setupNote="Note", + ) + assert calculate_rehearsal_priority(role) == RehearsalPriority.HIGH