"""Tests for diarize's pure parts. The pyannote pipeline itself is not loaded here.""" import sys from collections import namedtuple from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src")) import diarize # noqa: E402 Segment = namedtuple("Segment", "start end") class TestTurnsFromTracks: def test_diarize_turns_from_tracks_converts_and_sorts(self): """Normal: (segment, track, label) triples become sorted turn dicts.""" tracks = [(Segment(5.0, 9.25), "_", "SPEAKER_01"), (Segment(0.5, 4.0), "_", "SPEAKER_00")] assert diarize.turns_from_tracks(tracks) == [ {"start": 0.5, "end": 4.0, "speaker": "SPEAKER_00"}, {"start": 5.0, "end": 9.25, "speaker": "SPEAKER_01"}, ] def test_diarize_turns_from_tracks_rounds_to_milliseconds(self): """Boundary: float noise from the model is rounded away.""" tracks = [(Segment(0.03096875, 1.9980000000000002), "_", "SPEAKER_00")] assert diarize.turns_from_tracks(tracks) == [ {"start": 0.031, "end": 1.998, "speaker": "SPEAKER_00"} ] def test_diarize_turns_from_tracks_drops_empty_segments(self): """Boundary: zero or negative length segments carry no speech.""" tracks = [(Segment(2.0, 2.0), "_", "SPEAKER_00"), (Segment(3.0, 2.5), "_", "SPEAKER_00")] assert diarize.turns_from_tracks(tracks) == [] def test_diarize_turns_from_tracks_empty_input_is_empty_list(self): """Boundary: no tracks.""" assert diarize.turns_from_tracks([]) == [] class TestParseArgs: def test_diarize_parse_args_speakers_sets_exact_count(self): """Normal: --speakers pins the count.""" args = diarize.parse_args(["a.wav", "out.json", "--speakers", "3"]) assert (args.audio, args.out, args.speakers) == ("a.wav", "out.json", 3) def test_diarize_parse_args_defaults_let_the_model_estimate(self): """Normal: no count given.""" args = diarize.parse_args(["a.wav", "out.json"]) assert args.speakers is None and args.min_speakers is None and args.max_speakers is None @pytest.mark.parametrize("argv", [ ["a.wav", "out.json", "--speakers", "0"], ["a.wav", "out.json", "--speakers", "-2"], ["a.wav", "out.json", "--speakers", "three"], ["a.wav", "out.json", "--speakers", "3", "--max-speakers", "5"], ["a.wav", "out.json", "--min-speakers", "4", "--max-speakers", "2"], ["a.wav"], ]) def test_diarize_parse_args_rejects_bad_counts(self, argv): """Error: non-positive, non-numeric, contradictory or missing arguments.""" with pytest.raises(SystemExit): diarize.parse_args(argv) class TestPipelineKwargs: def test_diarize_pipeline_kwargs_only_passes_what_was_given(self): """Normal: unset options are not forwarded to the model.""" args = diarize.parse_args(["a.wav", "o.json", "--min-speakers", "2", "--max-speakers", "4"]) assert diarize.pipeline_kwargs(args) == {"min_speakers": 2, "max_speakers": 4} args = diarize.parse_args(["a.wav", "o.json", "--speakers", "3"]) assert diarize.pipeline_kwargs(args) == {"num_speakers": 3} assert diarize.pipeline_kwargs(diarize.parse_args(["a.wav", "o.json"])) == {}