mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 05:23:41 +08:00
68 lines
3.0 KiB
Python
68 lines
3.0 KiB
Python
from types import SimpleNamespace
|
|
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
|
|
from openpilot.selfdrive.ui import soundd
|
|
from openpilot.starpilot.audio import native_playback
|
|
|
|
|
|
def device():
|
|
return SimpleNamespace(_terminate=Mock(), _initialize=Mock(), OutputStream=Mock(return_value=object()))
|
|
|
|
|
|
def daemon():
|
|
obj = soundd.Soundd.__new__(soundd.Soundd)
|
|
obj.native_audio = None
|
|
return obj
|
|
|
|
|
|
def test_host_backend_reports_python_without_attempting_native():
|
|
obj, sd = daemon(), device()
|
|
with patch.object(soundd, 'PC', True), patch.object(native_playback, 'NativePlayback') as ctor:
|
|
assert soundd.Soundd.get_stream.__wrapped__(obj, sd) is sd.OutputStream.return_value
|
|
assert (obj.audio_backend, obj.audio_fallback_reason) == ('python', 'host')
|
|
ctor.assert_not_called()
|
|
assert sd.OutputStream.call_args.kwargs == {'channels': 1, 'samplerate': 48000, 'callback': obj.callback, 'blocksize': 4096}
|
|
|
|
|
|
def test_native_backend_reports_native_without_python_stream():
|
|
obj, sd = daemon(), device()
|
|
playback = Mock()
|
|
with patch.object(soundd, 'PC', False), patch.object(native_playback, 'NativePlayback', return_value=playback):
|
|
assert soundd.Soundd.get_stream.__wrapped__(obj, sd) is playback.stream.return_value
|
|
assert obj.native_audio is playback
|
|
assert (obj.audio_backend, obj.audio_fallback_reason) == ('native', None)
|
|
sd.OutputStream.assert_not_called()
|
|
playback.close.assert_not_called()
|
|
|
|
|
|
@pytest.mark.parametrize('exception', (OSError, AttributeError, ValueError, MemoryError))
|
|
def test_constructor_failure_preserves_python_audio_and_bounded_reason(exception):
|
|
obj, sd = daemon(), device()
|
|
with patch.object(soundd, 'PC', False), patch.object(native_playback, 'NativePlayback', side_effect=exception('private arbitrary detail')):
|
|
assert soundd.Soundd.get_stream.__wrapped__(obj, sd) is sd.OutputStream.return_value
|
|
assert obj.native_audio is None
|
|
assert (obj.audio_backend, obj.audio_fallback_reason) == ('python', 'initialization:' + exception.__name__)
|
|
|
|
|
|
@pytest.mark.parametrize('exception', (AttributeError, TypeError, ValueError))
|
|
def test_native_stream_unsupported_preserves_close_and_fallback(exception):
|
|
obj, sd = daemon(), device()
|
|
playback = Mock()
|
|
playback.stream.side_effect = exception('private arbitrary detail')
|
|
with patch.object(soundd, 'PC', False), patch.object(native_playback, 'NativePlayback', return_value=playback):
|
|
assert soundd.Soundd.get_stream.__wrapped__(obj, sd) is sd.OutputStream.return_value
|
|
playback.close.assert_called_once_with()
|
|
assert (obj.audio_backend, obj.audio_fallback_reason) == ('python', 'stream:' + exception.__name__)
|
|
|
|
|
|
def test_native_backend_unhandled_failure_closes_and_remains_an_error():
|
|
obj, sd = daemon(), device()
|
|
playback = Mock()
|
|
playback.stream.side_effect = OSError('backend open failed')
|
|
with patch.object(soundd, 'PC', False), patch.object(native_playback, 'NativePlayback', return_value=playback), pytest.raises(OSError):
|
|
soundd.Soundd.get_stream.__wrapped__(obj, sd)
|
|
playback.close.assert_called_once_with()
|
|
sd.OutputStream.assert_not_called()
|