from pathlib import Path from serato_doctor.matching import MatchingEngine, score_candidate from serato_doctor.models.reference import TrackReference from serato_doctor.models.track import DiskTrack def reference(filename, folder="House"): return TrackReference( Path("Test.crate"), Path("/old") / folder / filename, filename ) def track(filename, folder="House"): path = Path("/new") / folder / filename return DiskTrack(path, filename, 100, path.suffix.lower()) def test_exact_candidate_has_full_evidence_score(): match = score_candidate(reference("Track.mp3"), track("Track.mp3")) assert match.score == 90 assert match.max_score == 90 assert match.score_percent == 100.0 assert all(item.matched for item in match.evidence) def test_cloud_conflict_suffix_is_explained(): match = score_candidate(reference("Track.mp3"), track("Track 2.mp3")) assert match.score == 80 assert match.score_percent == 88.9 assert match.evidence[0].explanation == ( "Filename matches after removing a numeric conflict suffix" ) def test_case_normalized_match_scores_below_exact(): match = score_candidate(reference("TRACK.MP3"), track("track.mp3")) assert match.score == 85 assert match.evidence[0].points == 55 def test_engine_omits_unrelated_filenames(): engine = MatchingEngine([track("Different.mp3")]) assert engine.candidates_for(reference("Missing.mp3")) == () def test_ambiguous_candidates_are_ranked_deterministically(): engine = MatchingEngine( [track("Track 2.mp3", "Other"), track("Track 3.mp3", "House")] ) matches = engine.candidates_for(reference("Track.mp3")) assert [match.track.filename for match in matches] == [ "Track 3.mp3", "Track 2.mp3", ] assert [match.score for match in matches] == [80, 60]