129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
"""What the app does when the config leaves the hardware out.
|
|
|
|
Both of these are deliberately warnings rather than errors: a spare machine running
|
|
only the web front-end is a supported way to use this, and it should say so once at
|
|
startup rather than fail or - worse - look like it is working when it is not.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from musicmouse.__main__ import _build_player, wants_hardware
|
|
from musicmouse.bus import EventBus
|
|
from musicmouse.clock import RealClock
|
|
from musicmouse.config import SIMULATE, Config, ConfigError, load_config
|
|
from musicmouse.devices.null_transport import NullTransport
|
|
from musicmouse.simulator.fake_player import FakePlayer
|
|
from tests.conftest import VALID_CONFIG, write_config
|
|
|
|
|
|
def _config(config_dir: Path, *, drop: tuple[str, ...] = (), **general: Any) -> Config:
|
|
data = copy.deepcopy(VALID_CONFIG)
|
|
data["general"].update(general)
|
|
for key in drop:
|
|
data["general"].pop(key, None)
|
|
return load_config(write_config(config_dir, data))
|
|
|
|
|
|
# ------------------------------------------------------------------- serial port
|
|
|
|
|
|
def test_a_missing_serial_port_is_an_error(config_dir: Path) -> None:
|
|
"""Simulation has to be asked for. A config that lost the line must not boot."""
|
|
with pytest.raises(ConfigError) as excinfo:
|
|
_config(config_dir, drop=("serial_port",))
|
|
assert "general.serial_port" in str(excinfo.value)
|
|
assert "required" in str(excinfo.value)
|
|
|
|
|
|
def test_a_missing_alsa_device_is_an_error(config_dir: Path) -> None:
|
|
with pytest.raises(ConfigError) as excinfo:
|
|
_config(config_dir, drop=("alsa_device",))
|
|
assert "general.alsa_device" in str(excinfo.value)
|
|
assert "required" in str(excinfo.value)
|
|
|
|
|
|
def test_both_missing_are_reported_together(config_dir: Path) -> None:
|
|
with pytest.raises(ConfigError) as excinfo:
|
|
_config(config_dir, drop=("serial_port", "alsa_device"))
|
|
message = str(excinfo.value)
|
|
assert "2 problems" in message
|
|
assert "general.serial_port" in message
|
|
assert "general.alsa_device" in message
|
|
|
|
|
|
def test_simulate_switches_off_the_serial_link(
|
|
config_dir: Path, caplog: pytest.LogCaptureFixture
|
|
) -> None:
|
|
config = _config(config_dir, serial_port=SIMULATE)
|
|
assert config.general.serial_simulated is True
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
assert wants_hardware(config, False) is False
|
|
assert "running without the mouse" in caplog.text
|
|
|
|
|
|
def test_a_real_port_is_used(config_dir: Path) -> None:
|
|
config = _config(config_dir)
|
|
assert config.general.serial_simulated is False
|
|
assert wants_hardware(config, False) is True
|
|
|
|
|
|
def test_the_flag_wins_over_a_configured_port(config_dir: Path) -> None:
|
|
assert wants_hardware(_config(config_dir), True) is False
|
|
|
|
|
|
# ------------------------------------------------------------------ audio device
|
|
|
|
|
|
async def test_simulate_gives_a_silent_player(
|
|
config_dir: Path, caplog: pytest.LogCaptureFixture
|
|
) -> None:
|
|
bus = EventBus()
|
|
await bus.start()
|
|
try:
|
|
general = _config(config_dir, alsa_device=SIMULATE).general
|
|
assert general.audio_simulated is True
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
player = _build_player(bus, general, clock=RealClock())
|
|
|
|
assert isinstance(player, FakePlayer)
|
|
assert "alsa_device" in caplog.text
|
|
assert "nothing will be audible" in caplog.text
|
|
# The clamps still come from the config, so volume behaves the same either way.
|
|
assert player.volume == 40
|
|
player.set_volume(999)
|
|
assert player.volume == 60
|
|
finally:
|
|
player.close()
|
|
await bus.stop()
|
|
|
|
|
|
async def test_an_alsa_device_asks_for_the_real_player(config_dir: Path) -> None:
|
|
"""Only that it tries: instantiating VlcPlayer needs libVLC, which CI has not got."""
|
|
bus = EventBus()
|
|
await bus.start()
|
|
try:
|
|
general = _config(config_dir, alsa_device="default").general
|
|
assert general.audio_simulated is False
|
|
with pytest.raises(Exception): # noqa: B017 - ImportError or an OSError from libVLC
|
|
_build_player(bus, general, clock=RealClock())
|
|
finally:
|
|
await bus.stop()
|
|
|
|
|
|
# ---------------------------------------------------------------- null transport
|
|
|
|
|
|
def test_the_null_transport_drops_what_it_is_handed() -> None:
|
|
transport = NullTransport()
|
|
transport.write(b"\x00\x01\x02")
|
|
assert transport.connected is False
|