# -*- 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