diff --git a/inn_listen/tests/test_core.py b/inn_listen/tests/test_core.py new file mode 100644 index 0000000..536e044 --- /dev/null +++ b/inn_listen/tests/test_core.py @@ -0,0 +1,82 @@ +import pytest +import numpy as np +from unittest.mock import patch, MagicMock +from datetime import datetime +from pathlib import Path +import json + +import sys +import logging + +# Importiere das zu testende Modul +import inn_listen.core as core + +@pytest.fixture +def synthetic_signal(): + # Erzeugt ein synthetisches 50Hz-Signal mit Rauschen + fs = 1000 + t = np.linspace(0, 1, fs, endpoint=False) + signal = np.sin(2 * np.pi * 50 * t) + 0.01 * np.random.randn(fs) + return signal + +@pytest.fixture +def mock_audio_data(tmp_path): + return { + "timestamp": datetime.utcnow().isoformat(), + "frequency": 123.4, + "amplitude": 0.56, + "pattern": "harmonic" + } + +def test_start_stream_nominal(monkeypatch): + # Mock sounddevice.Stream + mock_stream = MagicMock() + monkeypatch.setattr(core, "sd", MagicMock(Stream=MagicMock(return_value=mock_stream))) + + log_output = core.start_stream("contact", -12.0, 1024) + assert isinstance(log_output, str) + assert "contact" in log_output or "Audio" in log_output + + +def test_start_stream_invalid_types(): + # Überprüft Typvalidierung + with pytest.raises((TypeError, ValueError)): + core.start_stream(123, "invalid", "fft") + + +def test_notch_filter_removes_frequency(synthetic_signal): + # Führt den Filter aus und überprüft, dass nicht identisch + filtered = core.notch_filter(synthetic_signal, freq=50.0, Q=30.0) + assert isinstance(filtered, np.ndarray) + assert filtered.shape == synthetic_signal.shape + diff_energy = np.sum(np.abs(filtered - synthetic_signal)) + assert diff_energy > 0.0 + + +def test_notch_filter_invalid_inputs(): + with pytest.raises((TypeError, ValueError)): + core.notch_filter("not-an-array", 50.0, 30.0) + + +def test_audio_data_json_serialization(mock_audio_data, tmp_path): + output_file = tmp_path / "analysis.json" + with open(output_file, "w", encoding="utf-8") as fp: + json.dump(mock_audio_data, fp) + # Validate structure + with open(output_file, "r", encoding="utf-8") as fp: + restored = json.load(fp) + for field in ["timestamp", "frequency", "amplitude", "pattern"]: + assert field in restored + assert isinstance(restored["pattern"], str) + + +def test_cli_invocation(monkeypatch): + mock_start_stream = MagicMock(return_value="Stream started") + monkeypatch.setattr(core, "start_stream", mock_start_stream) + + test_args = ["prog", "--mic", "contact", "--gain", "-12.0", "--fft", "2048"] + monkeypatch.setattr(sys, "argv", test_args) + with patch("builtins.print") as mock_print: + core.main() + mock_start_stream.assert_called_once() + mock_print.assert_called()