import numpy as np import pytest from morse_gen import morse_audio from bandsaunter.morse import decode_morse, encode_morse FS = 16000 MESSAGES = [ ("CQ CQ DE W1AW K", 18, 25), ("SOS SOS", 12, 20), ("TEST DE N0CALL 599 TU", 25, 18), ("HELLO WORLD 73", 35, 15), ("PARIS PARIS", 8, 25), ("VVV DE K1ABC", 22, 12), ("QRZ? DE VE3XYZ/M", 20, 20), ("R 5NN TU 73 GL", 30, 22), ("MAYDAY MAYDAY", 15, 8), ("THE QUICK BROWN FOX 1234567890", 28, 20), ("CQ DX DE W1AW", 18, 6), ] @pytest.mark.parametrize("msg,wpm,snr", MESSAGES) def test_decodes_exactly(msg, wpm, snr): r = decode_morse(morse_audio(msg, wpm, FS, snr), FS) assert r.text.strip() == msg assert r.is_morse @pytest.mark.parametrize("wpm", [8, 15, 22, 30, 40]) def test_speed_estimate_is_accurate(wpm): r = decode_morse(morse_audio("CQ DE W1AW TEST", wpm, FS, 20), FS) assert r.wpm == pytest.approx(wpm, rel=0.10) def test_tone_frequency_found(): r = decode_morse(morse_audio("CQ TEST", 20, FS, 20, tone=1100.0), FS) assert r.tone_hz == pytest.approx(1100.0, abs=25) def test_noise_is_not_morse(): rng = np.random.default_rng(0) r = decode_morse(0.1 * rng.standard_normal(FS * 3), FS) assert not r.is_morse assert r.text == "" def test_silence_is_rejected(): assert not decode_morse(np.zeros(FS * 2), FS).is_morse def test_encode_round_trip(): assert encode_morse("SOS") == "... --- ..." assert encode_morse("A B") == ".- / -..."