"""VTT syntax, independent repeated speech, and source segment validation."""
import pytest
from transcribe import parse_vtt, normalize_segments
def parse(tmp_path, body):
path = tmp_path / 'captions.vtt'
path.write_text(body, encoding='utf-8')
return parse_vtt(str(path))
def test_blocks_ids_settings_padding_and_missing_separator(tmp_path):
out = parse(tmp_path, '\ufeffWEBVTT\r\n\r\nNOTE comment\r\n00:00.000 --> 00:01.000\r\nskip\r\n\r\nSTYLE\r\n::cue {}\r\n\r\nREGION\r\nid:one\r\n\r\ncue-id\r\n00:01.000 --> 00:02.000 align:start\r\nfirst\r\n \r\nlast\r\n00:03.000 --> 00:04.000\r\nnext\r\n')
assert [s['text'] for s in out] == ['first last', 'next']
def test_valid_long_hours_and_invalid_minutes(tmp_path):
out = parse(tmp_path, 'WEBVTT\n\n100:02:03.004 --> 100:02:04.000\nx\n\n00:60.000 --> 01:01.000\ninvalid\n')
assert len(out) == 1 and out[0]['start'] == 360123.004
def test_overlapping_prefix_only_and_mixed_karaoke(tmp_path):
out = parse(tmp_path, 'WEBVTT\n\n00:01.000 --> 00:03.000\nThank you\n\n00:02.000 --> 00:04.000\nThank you all\n\n00:04.000 --> 00:05.000\nThank you all\n\n00:05.000 --> 00:06.000\nplain <00:05.100>spoken ending <literal>\n')
assert [s['text'] for s in out] == ['Thank you all', 'Thank you all', 'plain spoken ending ']
@pytest.mark.parametrize('segment', [
{'start': float('nan'), 'end': 1, 'text': 'hi'}, {'start': 2, 'end': 1, 'text': 'hi'},
{'start': True, 'end': 1, 'text': 'hi'}, {'start': 0, 'end': 1, 'text': ' '},
{'start': 0, 'end': float('inf'), 'text': 'hi'},
])
def test_rejects_invalid_segments(segment):
with pytest.raises((ValueError, TypeError)):
normalize_segments({'segments': [segment]})
def test_overlapping_separate_display_regions_are_not_merged(tmp_path):
out = parse(tmp_path, 'WEBVTT\n\n00:00.000 --> 00:02.000 line:10%\nHello\n\n00:01.000 --> 00:03.000 line:90%\nHello\n')
assert len(out) == 2
assert all(set(s) == {'start', 'end', 'text'} for s in out)