198 lines
7.5 KiB
Python
198 lines
7.5 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)
|
|
"""
|
|
|
|
from __future__ import unicode_literals # So that we can format strings with Unicode characters
|
|
import random
|
|
import sys
|
|
from StringIO import StringIO
|
|
|
|
from robot_interface.utils.microphone import (
|
|
choose_mic_default,
|
|
choose_mic_interactive,
|
|
choose_mic_arguments,
|
|
choose_mic,
|
|
get_microphones,
|
|
)
|
|
|
|
|
|
class MicrophoneUtils(object):
|
|
"""Shared tests for any PyAudio-like implementation, e.g. mock and real."""
|
|
|
|
def test_choose_mic_default(self, pyaudio_instance):
|
|
"""
|
|
Tests that the default microphone selection function returns a valid
|
|
microphone dictionary containing all necessary keys with correct types and values.
|
|
|
|
The result must contain at least "index", as this is used to identify the microphone,
|
|
and "name" for logging. It must have one or more channels (`maxInputChannels`),
|
|
and a default sample rate of at least 16000 Hz.
|
|
"""
|
|
result = choose_mic_default(pyaudio_instance)
|
|
assert "index" in result
|
|
assert isinstance(result["index"], (int, long))
|
|
|
|
assert "name" in result
|
|
assert isinstance(result["name"], (str, unicode))
|
|
|
|
assert "maxInputChannels" in result
|
|
assert isinstance(result["maxInputChannels"], (int, long))
|
|
assert result["maxInputChannels"] > 0
|
|
|
|
assert "defaultSampleRate" in result
|
|
assert isinstance(result["defaultSampleRate"], float)
|
|
assert result["defaultSampleRate"] >= 16000
|
|
|
|
def test_choose_mic_interactive_input_not_int(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests the robustness of the interactive selection when the user first enters
|
|
a non-integer value, ensuring the system prompts again without error and accepts
|
|
a valid integer on the second attempt.
|
|
"""
|
|
microphones = get_microphones(pyaudio_instance)
|
|
target_microphone = next(microphones)
|
|
|
|
mock_input = mocker.patch("__builtin__.raw_input", side_effect=["not an integer", "0"])
|
|
fake_out = StringIO()
|
|
mocker.patch.object(sys, "stdout", fake_out)
|
|
|
|
result = choose_mic_interactive(pyaudio_instance)
|
|
assert "index" in result
|
|
assert isinstance(result["index"], (int, long))
|
|
assert result["index"] == target_microphone["index"]
|
|
|
|
assert mock_input.called
|
|
|
|
assert any(p.startswith("Please enter a number") for p in fake_out.getvalue().splitlines())
|
|
|
|
def test_choose_mic_interactive_negative_index(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests that the interactive selection method prevents the user from entering
|
|
a negative integer as a microphone index.
|
|
"""
|
|
microphones = get_microphones(pyaudio_instance)
|
|
target_microphone = next(microphones)
|
|
|
|
mock_input = mocker.patch("__builtin__.raw_input", side_effect=["-1", "0"])
|
|
fake_out = StringIO()
|
|
mocker.patch.object(sys, "stdout", fake_out)
|
|
|
|
result = choose_mic_interactive(pyaudio_instance)
|
|
assert "index" in result
|
|
assert isinstance(result["index"], (int, long))
|
|
assert result["index"] == target_microphone["index"]
|
|
|
|
assert mock_input.called
|
|
|
|
assert any(p.startswith("Please enter a number") for p in fake_out.getvalue().splitlines())
|
|
|
|
def test_choose_mic_interactive_index_too_high(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests that the interactive selection method prevents the user from entering
|
|
an index that exceeds the total number of available microphones.
|
|
"""
|
|
real_count = len(list(get_microphones(pyaudio_instance)))
|
|
mock_input = mocker.patch("__builtin__.raw_input", side_effect=[str(real_count), "0"])
|
|
fake_out = StringIO()
|
|
mocker.patch.object(sys, "stdout", fake_out)
|
|
|
|
result = choose_mic_interactive(pyaudio_instance)
|
|
assert "index" in result
|
|
assert isinstance(result["index"], (int, long))
|
|
|
|
assert mock_input.called
|
|
|
|
assert any(p.startswith("Please enter a number") for p in fake_out.getvalue().splitlines())
|
|
|
|
def test_choose_mic_interactive_random_index(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests the core interactive functionality by simulating the selection of a
|
|
random valid microphone index and verifying that the correct microphone
|
|
information is returned.
|
|
"""
|
|
microphones = list(get_microphones(pyaudio_instance))
|
|
random_index = random.randrange(len(microphones))
|
|
mocker.patch("__builtin__.raw_input", side_effect=[str(random_index)])
|
|
|
|
result = choose_mic_interactive(pyaudio_instance)
|
|
assert "index" in result
|
|
assert isinstance(result["index"], (int, long))
|
|
assert result["index"] == microphones[random_index]["index"]
|
|
|
|
def test_choose_mic_no_arguments(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests `choose_mic_arguments` when no command-line arguments are provided,
|
|
"""
|
|
mocker.patch.object(sys, "argv", [])
|
|
|
|
result = choose_mic_arguments(pyaudio_instance)
|
|
|
|
assert result is None
|
|
|
|
def test_choose_mic_arguments(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests `choose_mic_arguments` when the microphone name is passed as a separate
|
|
argument.
|
|
"""
|
|
for mic in get_microphones(pyaudio_instance):
|
|
mocker.patch.object(sys, "argv", ["--microphone", mic["name"]])
|
|
|
|
result = choose_mic_arguments(pyaudio_instance)
|
|
|
|
assert result is not None
|
|
assert result == mic
|
|
|
|
def test_choose_mic_arguments_eq(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests `choose_mic_arguments` when the microphone name is passed using an
|
|
equals sign (`--microphone=NAME`).
|
|
"""
|
|
for mic in get_microphones(pyaudio_instance):
|
|
mocker.patch.object(sys, "argv", ["--microphone={}".format(mic["name"])])
|
|
|
|
result = choose_mic_arguments(pyaudio_instance)
|
|
|
|
assert result is not None
|
|
assert result == mic
|
|
|
|
def test_choose_mic_arguments_not_exist(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests `choose_mic_arguments` when a non-existent microphone name is passed
|
|
via command-line arguments, expecting the function to return None.
|
|
"""
|
|
mocker.patch.object(sys, "argv", ["--microphone", "Surely this microphone doesn't exist"])
|
|
|
|
result = choose_mic_arguments(pyaudio_instance)
|
|
|
|
assert result is None
|
|
|
|
def test_choose_mic_with_argument(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests `choose_mic` function when a valid microphone is
|
|
specified via command-line arguments.
|
|
"""
|
|
mic = next(get_microphones(pyaudio_instance))
|
|
mocker.patch.object(sys, "argv", ["--microphone", mic["name"]])
|
|
|
|
result = choose_mic(pyaudio_instance)
|
|
|
|
assert result is not None
|
|
assert result == mic
|
|
|
|
def test_choose_mic_no_argument(self, pyaudio_instance, mocker):
|
|
"""
|
|
Tests `choose_mic` function when no command-line arguments
|
|
are provided, verifying that the function falls back correctly to the
|
|
system's default microphone selection.
|
|
"""
|
|
default_mic = choose_mic_default(pyaudio_instance)
|
|
mocker.patch.object(sys, "argv", [])
|
|
|
|
result = choose_mic(pyaudio_instance)
|
|
|
|
assert result is not None
|
|
assert result == default_mic
|