Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 68 additions & 50 deletions services/analysis-engine/tests/test_priority.py
Original file line number Diff line number Diff line change
Expand Up @@ -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