import os import pytest from PyQt6.QtCore import QTime from PyQt6.QtMultimedia import QMediaPlayer from PyQt6.QtWidgets import QHBoxLayout from pytestqt.qtbot import QtBot from buzz.widgets.audio_player import AudioPlayer from tests.audio import test_audio_path from buzz.settings.settings import Settings def assert_approximately_equal(actual, expected, tolerance=0.001): """Helper function to compare values with tolerance for floating-point precision""" assert abs(actual - expected) < tolerance, f"Value {actual} is not approximately equal to {expected}" class TestAudioPlayer: def test_should_load_audio(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) actual = os.path.normpath(widget.media_player.source().toLocalFile()) expected = os.path.normpath(test_audio_path) assert actual == expected def test_should_update_time_label(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) widget.on_duration_changed(2000) widget.on_position_changed(1000) position_time = QTime(0, 0).addMSecs(1000).toString() duration_time = QTime(0, 0).addMSecs(2000).toString() assert widget.time_label.text() == f"{position_time} / {duration_time}" def test_should_toggle_play_button_icon(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) widget.on_playback_state_changed(QMediaPlayer.PlaybackState.PlayingState) assert widget.play_button.icon().themeName() == widget.pause_icon.themeName() widget.on_playback_state_changed(QMediaPlayer.PlaybackState.PausedState) assert widget.play_button.icon().themeName() == widget.play_icon.themeName() widget.on_playback_state_changed(QMediaPlayer.PlaybackState.StoppedState) assert widget.play_button.icon().themeName() == widget.play_icon.themeName() def test_should_have_basic_audio_controls(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Speed controls were moved to transcription viewer - just verify basic audio player functionality assert widget.play_button is not None assert widget.scrubber is not None assert widget.time_label is not None # Verify the widget loads audio correctly assert widget.media_player is not None assert os.path.normpath(widget.media_player.source().toLocalFile()) == os.path.normpath(test_audio_path) def test_should_change_playback_rate_directly(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Speed controls moved to transcription viewer - test basic playback rate functionality initial_rate = widget.media_player.playbackRate() widget.media_player.setPlaybackRate(1.5) assert_approximately_equal(widget.media_player.playbackRate(), 1.5) def test_should_handle_custom_playback_rates(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Speed controls moved to transcription viewer - test basic playback rate functionality widget.media_player.setPlaybackRate(1.7) assert_approximately_equal(widget.media_player.playbackRate(), 1.7) def test_should_handle_various_playback_rates(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Speed controls moved to transcription viewer - test basic playback rate functionality # Test that the media player can handle various playback rates widget.media_player.setPlaybackRate(0.5) assert_approximately_equal(widget.media_player.playbackRate(), 0.5) widget.media_player.setPlaybackRate(2.0) assert_approximately_equal(widget.media_player.playbackRate(), 2.0) def test_should_use_single_row_layout(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Verify the layout structure layout = widget.layout() assert isinstance(layout, QHBoxLayout) # Speed controls moved to transcription viewer - simplified layout assert layout.count() == 3 # play_button, scrubber, time_label def test_should_persist_playback_rate_setting(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Speed controls moved to transcription viewer - test that settings are loaded # The widget should load the saved playback rate from settings assert widget.settings is not None saved_rate = widget.settings.value(Settings.Key.AUDIO_PLAYBACK_RATE, 1.0, float) assert isinstance(saved_rate, float) assert 0.1 <= saved_rate <= 5.0 def test_should_handle_range_looping(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Test range setting and looping functionality widget.set_range((1000, 3000)) # 1-3 seconds assert widget.range_ms == (1000, 3000) # Clear range widget.clear_range() assert widget.range_ms is None def test_should_handle_invalid_media(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) widget.set_invalid_media(True) # Speed controls moved to transcription viewer - just verify invalid media handling assert widget.invalid_media is True assert widget.play_button.isEnabled() is False assert widget.scrubber.isEnabled() is False assert widget.time_label.isEnabled() is False def test_should_stop_playback(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Test stop functionality widget.stop() assert widget.media_player.playbackState() == QMediaPlayer.PlaybackState.StoppedState def test_should_handle_media_status_changes(self, qtbot: QtBot): widget = AudioPlayer(test_audio_path) qtbot.add_widget(widget) # Test media status handling widget.on_media_status_changed(QMediaPlayer.MediaStatus.LoadedMedia) assert widget.invalid_media is False widget.on_media_status_changed(QMediaPlayer.MediaStatus.InvalidMedia) assert widget.invalid_media is True