139 lines
4.3 KiB
Python
139 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
This program has been developed by students from the bachelor Computer Science at Utrecht
|
||
University within the Software Project course.
|
||
© Copyright Utrecht University (Department of Information and Computing Sciences)
|
||
"""
|
||
|
||
import mock
|
||
import pytest
|
||
|
||
from common.microphone_utils import MicrophoneUtils
|
||
from robot_interface.utils.microphone import choose_mic_default, choose_mic_interactive
|
||
|
||
|
||
class MockPyAudio:
|
||
"""
|
||
A mock implementation of the PyAudio library class, designed for testing
|
||
microphone utility functions without requiring actual audio hardware.
|
||
|
||
It provides fake devices, including one input microphone, and implements
|
||
the core PyAudio methods required for device enumeration.
|
||
|
||
:ivar devices: A list of dictionaries representing mock audio devices.
|
||
:vartype devices: List[Dict[str, Any]]
|
||
"""
|
||
def __init__(self):
|
||
# You can predefine fake device info here
|
||
self.devices = [
|
||
{
|
||
"index": 0,
|
||
"name": u"Someone’s Microphone", # Using a Unicode ’ character
|
||
"maxInputChannels": 2,
|
||
"maxOutputChannels": 0,
|
||
"defaultSampleRate": 44100.0,
|
||
"defaultLowInputLatency": 0.01,
|
||
"defaultLowOutputLatency": 0.01,
|
||
"defaultHighInputLatency": 0.1,
|
||
"defaultHighOutputLatency": 0.1,
|
||
"hostApi": 0,
|
||
},
|
||
{
|
||
"index": 1,
|
||
"name": u"Mock Speaker 1",
|
||
"maxInputChannels": 0,
|
||
"maxOutputChannels": 2,
|
||
"defaultSampleRate": 48000.0,
|
||
"defaultLowInputLatency": 0.01,
|
||
"defaultLowOutputLatency": 0.01,
|
||
"defaultHighInputLatency": 0.1,
|
||
"defaultHighOutputLatency": 0.1,
|
||
"hostApi": 0,
|
||
},
|
||
]
|
||
|
||
def get_device_count(self):
|
||
"""
|
||
Returns the number of available mock devices.
|
||
|
||
:return: The total number of devices in the mock list.
|
||
:rtype: int
|
||
"""
|
||
return len(self.devices)
|
||
|
||
def get_device_info_by_index(self, index):
|
||
"""
|
||
Returns information for a given mock device index.
|
||
|
||
:param index: The index of the device to retrieve.
|
||
:type index: int
|
||
|
||
:return: A dictionary containing device information.
|
||
:rtype: Dict[str, Any]
|
||
"""
|
||
if 0 <= index < len(self.devices):
|
||
return self.devices[index]
|
||
else:
|
||
raise IOError("Invalid device index: {}".format(index))
|
||
|
||
def get_default_input_device_info(self):
|
||
"""
|
||
Returns information for the default mock input device.
|
||
|
||
:return: A dictionary containing the default input device information.
|
||
:rtype: Dict[str, Any]
|
||
"""
|
||
for device in self.devices:
|
||
if device.get("maxInputChannels", 0) > 0:
|
||
return device
|
||
raise IOError("No default input device found")
|
||
|
||
|
||
@pytest.fixture
|
||
def pyaudio_instance():
|
||
"""
|
||
A pytest fixture that returns an instance of the `MockPyAudio` class.
|
||
|
||
:return: An initialized instance of the mock PyAudio class.
|
||
:rtype: MockPyAudio
|
||
"""
|
||
return MockPyAudio()
|
||
|
||
|
||
def _raise_io_error():
|
||
"""
|
||
Helper function used to mock PyAudio methods that are expected to fail
|
||
when no device is available.
|
||
"""
|
||
raise IOError()
|
||
|
||
|
||
class TestAudioUnit(MicrophoneUtils):
|
||
"""
|
||
Runs the shared microphone behavior tests defined in `MicrophoneUtils` using
|
||
the mock PyAudio implementation.
|
||
"""
|
||
def test_choose_mic_default_no_mic(self):
|
||
"""
|
||
Tests `choose_mic_default` when no microphones are available.
|
||
"""
|
||
mock_pyaudio = mock.Mock()
|
||
mock_pyaudio.get_device_count = mock.Mock(return_value=0L)
|
||
mock_pyaudio.get_default_input_device_info = _raise_io_error
|
||
|
||
result = choose_mic_default(mock_pyaudio)
|
||
|
||
assert result is None
|
||
|
||
def test_choose_mic_interactive_no_mic(self):
|
||
"""
|
||
Tests `choose_mic_interactive` when no microphones are available.
|
||
"""
|
||
mock_pyaudio = mock.Mock()
|
||
mock_pyaudio.get_device_count = mock.Mock(return_value=0L)
|
||
mock_pyaudio.get_default_input_device_info = _raise_io_error
|
||
|
||
result = choose_mic_interactive(mock_pyaudio)
|
||
|
||
assert result is None
|