mirror of
https://github.com/chidiwilliams/buzz.git
synced 2026-03-14 14:45:46 +01:00
Adding speaker_identification_widget tests
This commit is contained in:
parent
3fe9731aa7
commit
6d95085510
3 changed files with 234 additions and 13 deletions
|
|
@ -8,5 +8,12 @@ omit =
|
|||
deepmultilingualpunctuation/*
|
||||
ctc_forced_aligner/*
|
||||
|
||||
[report]
|
||||
exclude_also =
|
||||
if sys.platform == "win32":
|
||||
if platform.system\(\) == "Windows":
|
||||
if platform.system\(\) == "Linux":
|
||||
if platform.system\(\) == "Darwin":
|
||||
|
||||
[html]
|
||||
directory = coverage/html
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ def widget(qtbot: QtBot):
|
|||
mock_manager.finished.connect = MagicMock()
|
||||
w = HuggingFaceSearchLineEdit(network_access_manager=mock_manager)
|
||||
qtbot.add_widget(w)
|
||||
# Prevent popup.show() from triggering a Wayland fatal protocol error
|
||||
# in headless/CI environments where popup windows lack a transient parent.
|
||||
w.popup.show = MagicMock()
|
||||
return w
|
||||
|
||||
|
||||
|
|
@ -82,7 +85,7 @@ class TestHuggingFaceSearchLineEdit:
|
|||
mock_reply.readAll.return_value.data.return_value = json.dumps([]).encode()
|
||||
widget.on_request_response(mock_reply)
|
||||
assert widget.popup.count() == 0
|
||||
assert not widget.popup.isVisible()
|
||||
widget.popup.show.assert_not_called()
|
||||
|
||||
def test_on_request_response_item_has_user_role_data(self, widget):
|
||||
mock_reply = MagicMock(spec=QNetworkReply)
|
||||
|
|
@ -111,10 +114,10 @@ class TestHuggingFaceSearchLineEdit:
|
|||
item.setData(Qt.ItemDataRole.UserRole, "openai/whisper-tiny")
|
||||
widget.popup.addItem(item)
|
||||
widget.popup.setCurrentItem(item)
|
||||
widget.popup.show()
|
||||
|
||||
widget.on_select_item()
|
||||
assert not widget.popup.isVisible()
|
||||
with patch.object(widget.popup, 'hide') as mock_hide:
|
||||
widget.on_select_item()
|
||||
mock_hide.assert_called_once()
|
||||
|
||||
def test_on_popup_selected_stops_timer(self, widget):
|
||||
widget.timer.start()
|
||||
|
|
@ -128,19 +131,19 @@ class TestHuggingFaceSearchLineEdit:
|
|||
assert widget.eventFilter(other, event) is False
|
||||
|
||||
def test_event_filter_mouse_press_hides_popup(self, widget):
|
||||
widget.popup.show()
|
||||
event = MagicMock()
|
||||
event.type.return_value = QEvent.Type.MouseButtonPress
|
||||
result = widget.eventFilter(widget.popup, event)
|
||||
with patch.object(widget.popup, 'hide') as mock_hide:
|
||||
result = widget.eventFilter(widget.popup, event)
|
||||
assert result is True
|
||||
assert not widget.popup.isVisible()
|
||||
mock_hide.assert_called_once()
|
||||
|
||||
def test_event_filter_escape_hides_popup(self, widget, qtbot: QtBot):
|
||||
widget.popup.show()
|
||||
event = QKeyEvent(QEvent.Type.KeyPress, Qt.Key.Key_Escape, Qt.KeyboardModifier.NoModifier)
|
||||
result = widget.eventFilter(widget.popup, event)
|
||||
with patch.object(widget.popup, 'hide') as mock_hide:
|
||||
result = widget.eventFilter(widget.popup, event)
|
||||
assert result is True
|
||||
assert not widget.popup.isVisible()
|
||||
mock_hide.assert_called_once()
|
||||
|
||||
def test_event_filter_enter_selects_item(self, widget, qtbot: QtBot):
|
||||
item = QListWidgetItem("openai/whisper-tiny")
|
||||
|
|
@ -168,7 +171,7 @@ class TestHuggingFaceSearchLineEdit:
|
|||
assert widget.eventFilter(widget.popup, event) is False
|
||||
|
||||
def test_event_filter_other_key_hides_popup(self, widget):
|
||||
widget.popup.show()
|
||||
event = QKeyEvent(QEvent.Type.KeyPress, Qt.Key.Key_A, Qt.KeyboardModifier.NoModifier)
|
||||
widget.eventFilter(widget.popup, event)
|
||||
assert not widget.popup.isVisible()
|
||||
with patch.object(widget.popup, 'hide') as mock_hide:
|
||||
widget.eventFilter(widget.popup, event)
|
||||
mock_hide.assert_called_once()
|
||||
|
|
|
|||
|
|
@ -90,6 +90,217 @@ class TestSpeakerIdentificationWidget:
|
|||
assert (result == [[{'end_time': 8904, 'speaker': 'Speaker 0', 'start_time': 140, 'text': 'Bien venue dans. '}]]
|
||||
or result == [[{'end_time': 8904, 'speaker': 'Speaker 0', 'start_time': 140, 'text': 'Bienvenue dans. '}]])
|
||||
|
||||
def test_identify_button_toggles_visibility(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
# Before: identify visible, cancel hidden
|
||||
assert not widget.step_1_button.isHidden()
|
||||
assert widget.cancel_button.isHidden()
|
||||
|
||||
from PyQt6.QtCore import QThread as RealQThread
|
||||
mock_thread = MagicMock(spec=RealQThread)
|
||||
mock_thread.started = MagicMock()
|
||||
mock_thread.started.connect = MagicMock()
|
||||
|
||||
with patch.object(widget, '_cleanup_thread'), \
|
||||
patch('buzz.widgets.transcription_viewer.speaker_identification_widget.QThread', return_value=mock_thread), \
|
||||
patch.object(widget, 'worker', create=True):
|
||||
# patch moveToThread on IdentificationWorker to avoid type error
|
||||
with patch.object(IdentificationWorker, 'moveToThread'):
|
||||
widget.on_identify_button_clicked()
|
||||
|
||||
# After: identify hidden, cancel visible
|
||||
assert widget.step_1_button.isHidden()
|
||||
assert not widget.cancel_button.isHidden()
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_cancel_button_resets_ui(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
# Simulate identification started
|
||||
widget.step_1_button.setVisible(False)
|
||||
widget.cancel_button.setVisible(True)
|
||||
|
||||
with patch.object(widget, '_cleanup_thread'):
|
||||
widget.on_cancel_button_clicked()
|
||||
|
||||
assert not widget.step_1_button.isHidden()
|
||||
assert widget.cancel_button.isHidden()
|
||||
assert widget.progress_bar.value() == 0
|
||||
assert len(widget.progress_label.text()) > 0
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_progress_update_sets_label_and_bar(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
widget.on_progress_update("3/8 Loading alignment model")
|
||||
|
||||
assert widget.progress_label.text() == "3/8 Loading alignment model"
|
||||
assert widget.progress_bar.value() == 3
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_progress_update_step_8_enables_save(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
assert not widget.save_button.isEnabled()
|
||||
|
||||
widget.on_progress_update("8/8 Identification done")
|
||||
|
||||
assert widget.save_button.isEnabled()
|
||||
assert widget.step_2_group_box.isEnabled()
|
||||
assert widget.merge_speaker_sentences.isEnabled()
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_identification_finished_empty_result(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
initial_row_count = widget.speaker_preview_row.count()
|
||||
|
||||
widget.on_identification_finished([])
|
||||
|
||||
assert widget.identification_result == []
|
||||
# Empty result returns early — speaker preview row unchanged
|
||||
assert widget.speaker_preview_row.count() == initial_row_count
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_identification_finished_populates_speakers(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
result = [
|
||||
{'speaker': 'Speaker 0', 'start_time': 0, 'end_time': 3000, 'text': 'Hello world.'},
|
||||
{'speaker': 'Speaker 1', 'start_time': 3000, 'end_time': 6000, 'text': 'Hi there.'},
|
||||
]
|
||||
widget.on_identification_finished(result)
|
||||
|
||||
assert widget.identification_result == result
|
||||
# Two speaker rows should have been created
|
||||
assert widget.speaker_preview_row.count() == 2
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_identification_error_resets_buttons(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
widget.step_1_button.setVisible(False)
|
||||
widget.cancel_button.setVisible(True)
|
||||
|
||||
widget.on_identification_error("Some error")
|
||||
|
||||
assert not widget.step_1_button.isHidden()
|
||||
assert widget.cancel_button.isHidden()
|
||||
assert widget.progress_bar.value() == 0
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_save_no_merge(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
result = [
|
||||
{'speaker': 'Speaker 0', 'start_time': 0, 'end_time': 2000, 'text': 'Hello.'},
|
||||
{'speaker': 'Speaker 0', 'start_time': 2000, 'end_time': 4000, 'text': 'World.'},
|
||||
{'speaker': 'Speaker 1', 'start_time': 4000, 'end_time': 6000, 'text': 'Hi.'},
|
||||
]
|
||||
widget.on_identification_finished(result)
|
||||
widget.merge_speaker_sentences.setChecked(False)
|
||||
|
||||
with patch.object(widget.transcription_service, 'copy_transcription', return_value=uuid.uuid4()) as mock_copy, \
|
||||
patch.object(widget.transcription_service, 'update_transcription_as_completed') as mock_update:
|
||||
widget.on_save_button_clicked()
|
||||
|
||||
mock_copy.assert_called_once()
|
||||
mock_update.assert_called_once()
|
||||
segments = mock_update.call_args[0][1]
|
||||
# No merge: 3 entries → 3 segments
|
||||
assert len(segments) == 3
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_save_with_merge(self, qtbot: QtBot, transcription, transcription_service):
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
result = [
|
||||
{'speaker': 'Speaker 0', 'start_time': 0, 'end_time': 2000, 'text': 'Hello.'},
|
||||
{'speaker': 'Speaker 0', 'start_time': 2000, 'end_time': 4000, 'text': 'World.'},
|
||||
{'speaker': 'Speaker 1', 'start_time': 4000, 'end_time': 6000, 'text': 'Hi.'},
|
||||
]
|
||||
widget.on_identification_finished(result)
|
||||
widget.merge_speaker_sentences.setChecked(True)
|
||||
|
||||
with patch.object(widget.transcription_service, 'copy_transcription', return_value=uuid.uuid4()), \
|
||||
patch.object(widget.transcription_service, 'update_transcription_as_completed') as mock_update:
|
||||
widget.on_save_button_clicked()
|
||||
|
||||
segments = mock_update.call_args[0][1]
|
||||
# Merge: two consecutive Speaker 0 entries → merged into 1; Speaker 1 → 1 = 2 total
|
||||
assert len(segments) == 2
|
||||
assert "Speaker 0" in segments[0].text
|
||||
assert "Hello." in segments[0].text
|
||||
assert "World." in segments[0].text
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_on_save_emits_transcriptions_updated(self, qtbot: QtBot, transcription, transcription_service):
|
||||
updated_signal = MagicMock()
|
||||
widget = SpeakerIdentificationWidget(
|
||||
transcription=transcription,
|
||||
transcription_service=transcription_service,
|
||||
transcriptions_updated_signal=updated_signal,
|
||||
)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
result = [{'speaker': 'Speaker 0', 'start_time': 0, 'end_time': 1000, 'text': 'Hi.'}]
|
||||
widget.on_identification_finished(result)
|
||||
|
||||
new_id = uuid.uuid4()
|
||||
with patch.object(widget.transcription_service, 'copy_transcription', return_value=new_id), \
|
||||
patch.object(widget.transcription_service, 'update_transcription_as_completed'):
|
||||
widget.on_save_button_clicked()
|
||||
|
||||
updated_signal.emit.assert_called_once_with(new_id)
|
||||
|
||||
widget.close()
|
||||
|
||||
def test_batch_processing_with_many_words(self):
|
||||
"""Test batch processing when there are more than 200 words."""
|
||||
# Create mock punctuation model
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue