mirror of
https://github.com/smittix/intercept.git
synced 2026-07-08 01:28:13 -07:00
style: apply ruff-format to entire codebase
First-time run of ruff-format via pre-commit hook normalises quote style, trailing commas, and whitespace across 188 Python files. No logic changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+197
-160
@@ -13,21 +13,23 @@ import numpy as np
|
||||
def _login_session(client) -> None:
|
||||
"""Mark the Flask test session as authenticated."""
|
||||
with client.session_transaction() as sess:
|
||||
sess['logged_in'] = True
|
||||
sess['username'] = 'test'
|
||||
sess['role'] = 'admin'
|
||||
sess["logged_in"] = True
|
||||
sess["username"] = "test"
|
||||
sess["role"] = "admin"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Station database tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestWeFaxStations:
|
||||
"""WeFax station database tests."""
|
||||
|
||||
def test_load_stations_returns_list(self):
|
||||
"""load_stations() should return a non-empty list."""
|
||||
from utils.wefax_stations import load_stations
|
||||
|
||||
stations = load_stations()
|
||||
assert isinstance(stations, list)
|
||||
assert len(stations) >= 10
|
||||
@@ -35,8 +37,8 @@ class TestWeFaxStations:
|
||||
def test_station_has_required_fields(self):
|
||||
"""Each station must have required fields."""
|
||||
from utils.wefax_stations import load_stations
|
||||
required = {'name', 'callsign', 'country', 'city', 'coordinates',
|
||||
'frequencies', 'ioc', 'lpm', 'schedule'}
|
||||
|
||||
required = {"name", "callsign", "country", "city", "coordinates", "frequencies", "ioc", "lpm", "schedule"}
|
||||
for station in load_stations():
|
||||
missing = required - set(station.keys())
|
||||
assert not missing, f"Station {station.get('callsign', '?')} missing: {missing}"
|
||||
@@ -44,20 +46,23 @@ class TestWeFaxStations:
|
||||
def test_get_station_by_callsign(self):
|
||||
"""get_station() should return correct station."""
|
||||
from utils.wefax_stations import get_station
|
||||
station = get_station('NOJ')
|
||||
|
||||
station = get_station("NOJ")
|
||||
assert station is not None
|
||||
assert station['callsign'] == 'NOJ'
|
||||
assert station['country'] == 'US'
|
||||
assert station["callsign"] == "NOJ"
|
||||
assert station["country"] == "US"
|
||||
|
||||
def test_get_station_case_insensitive(self):
|
||||
"""get_station() should be case-insensitive."""
|
||||
from utils.wefax_stations import get_station
|
||||
assert get_station('noj') is not None
|
||||
|
||||
assert get_station("noj") is not None
|
||||
|
||||
def test_get_station_not_found(self):
|
||||
"""get_station() should return None for unknown callsign."""
|
||||
from utils.wefax_stations import get_station
|
||||
assert get_station('XXXXX') is None
|
||||
|
||||
assert get_station("XXXXX") is None
|
||||
|
||||
def test_resolve_tuning_frequency_auto_uses_carrier_for_known_station(self):
|
||||
"""Known station frequencies default to carrier-list behavior in auto mode."""
|
||||
@@ -65,12 +70,12 @@ class TestWeFaxStations:
|
||||
|
||||
tuned, reference, offset_applied = resolve_tuning_frequency_khz(
|
||||
listed_frequency_khz=4298.0,
|
||||
station_callsign='NOJ',
|
||||
frequency_reference='auto',
|
||||
station_callsign="NOJ",
|
||||
frequency_reference="auto",
|
||||
)
|
||||
|
||||
assert math.isclose(tuned, 4296.1, abs_tol=1e-6)
|
||||
assert reference == 'carrier'
|
||||
assert reference == "carrier"
|
||||
assert offset_applied is True
|
||||
|
||||
def test_resolve_tuning_frequency_auto_preserves_unknown_station_input(self):
|
||||
@@ -79,12 +84,12 @@ class TestWeFaxStations:
|
||||
|
||||
tuned, reference, offset_applied = resolve_tuning_frequency_khz(
|
||||
listed_frequency_khz=4298.0,
|
||||
station_callsign='',
|
||||
frequency_reference='auto',
|
||||
station_callsign="",
|
||||
frequency_reference="auto",
|
||||
)
|
||||
|
||||
assert math.isclose(tuned, 4298.0, abs_tol=1e-6)
|
||||
assert reference == 'dial'
|
||||
assert reference == "dial"
|
||||
assert offset_applied is False
|
||||
|
||||
def test_resolve_tuning_frequency_dial_override(self):
|
||||
@@ -93,12 +98,12 @@ class TestWeFaxStations:
|
||||
|
||||
tuned, reference, offset_applied = resolve_tuning_frequency_khz(
|
||||
listed_frequency_khz=4298.0,
|
||||
station_callsign='NOJ',
|
||||
frequency_reference='dial',
|
||||
station_callsign="NOJ",
|
||||
frequency_reference="dial",
|
||||
)
|
||||
|
||||
assert math.isclose(tuned, 4298.0, abs_tol=1e-6)
|
||||
assert reference == 'dial'
|
||||
assert reference == "dial"
|
||||
assert offset_applied is False
|
||||
|
||||
def test_resolve_tuning_frequency_rejects_invalid_reference(self):
|
||||
@@ -108,33 +113,35 @@ class TestWeFaxStations:
|
||||
try:
|
||||
resolve_tuning_frequency_khz(
|
||||
listed_frequency_khz=4298.0,
|
||||
station_callsign='NOJ',
|
||||
frequency_reference='invalid',
|
||||
station_callsign="NOJ",
|
||||
frequency_reference="invalid",
|
||||
)
|
||||
raise AssertionError("Expected ValueError for invalid frequency_reference")
|
||||
except ValueError as exc:
|
||||
assert 'frequency_reference' in str(exc)
|
||||
assert "frequency_reference" in str(exc)
|
||||
|
||||
def test_station_frequencies_have_khz(self):
|
||||
"""Each frequency entry must have 'khz' and 'description'."""
|
||||
from utils.wefax_stations import load_stations
|
||||
|
||||
for station in load_stations():
|
||||
for freq in station['frequencies']:
|
||||
assert 'khz' in freq, f"{station['callsign']} missing khz"
|
||||
assert 'description' in freq, f"{station['callsign']} missing description"
|
||||
assert isinstance(freq['khz'], (int, float))
|
||||
assert freq['khz'] > 0
|
||||
for freq in station["frequencies"]:
|
||||
assert "khz" in freq, f"{station['callsign']} missing khz"
|
||||
assert "description" in freq, f"{station['callsign']} missing description"
|
||||
assert isinstance(freq["khz"], (int, float))
|
||||
assert freq["khz"] > 0
|
||||
|
||||
def test_schedule_format(self):
|
||||
"""Schedule entries must have utc, duration_min, content."""
|
||||
from utils.wefax_stations import load_stations
|
||||
|
||||
for station in load_stations():
|
||||
for entry in station['schedule']:
|
||||
assert 'utc' in entry
|
||||
assert 'duration_min' in entry
|
||||
assert 'content' in entry
|
||||
for entry in station["schedule"]:
|
||||
assert "utc" in entry
|
||||
assert "duration_min" in entry
|
||||
assert "content" in entry
|
||||
# UTC format: HH:MM
|
||||
parts = entry['utc'].split(':')
|
||||
parts = entry["utc"].split(":")
|
||||
assert len(parts) == 2
|
||||
assert 0 <= int(parts[0]) <= 23
|
||||
assert 0 <= int(parts[1]) <= 59
|
||||
@@ -142,45 +149,52 @@ class TestWeFaxStations:
|
||||
def test_get_current_broadcasts(self):
|
||||
"""get_current_broadcasts() should return up to 3 entries."""
|
||||
from utils.wefax_stations import get_current_broadcasts
|
||||
broadcasts = get_current_broadcasts('NOJ')
|
||||
|
||||
broadcasts = get_current_broadcasts("NOJ")
|
||||
assert isinstance(broadcasts, list)
|
||||
assert len(broadcasts) <= 3
|
||||
for b in broadcasts:
|
||||
assert 'utc' in b
|
||||
assert 'content' in b
|
||||
assert "utc" in b
|
||||
assert "content" in b
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Decoder unit tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestWeFaxDecoder:
|
||||
"""WeFax decoder DSP and data class tests."""
|
||||
|
||||
def test_freq_to_pixel_black(self):
|
||||
"""1500 Hz should map to 0 (black)."""
|
||||
from utils.wefax import _freq_to_pixel
|
||||
|
||||
assert _freq_to_pixel(1500.0) == 0
|
||||
|
||||
def test_freq_to_pixel_white(self):
|
||||
"""2300 Hz should map to 255 (white)."""
|
||||
from utils.wefax import _freq_to_pixel
|
||||
|
||||
assert _freq_to_pixel(2300.0) == 255
|
||||
|
||||
def test_freq_to_pixel_mid(self):
|
||||
"""1900 Hz (carrier) should map to ~128."""
|
||||
from utils.wefax import _freq_to_pixel
|
||||
|
||||
val = _freq_to_pixel(1900.0)
|
||||
assert 120 <= val <= 135
|
||||
|
||||
def test_freq_to_pixel_clamp_low(self):
|
||||
"""Below 1500 Hz should clamp to 0."""
|
||||
from utils.wefax import _freq_to_pixel
|
||||
|
||||
assert _freq_to_pixel(1000.0) == 0
|
||||
|
||||
def test_freq_to_pixel_clamp_high(self):
|
||||
"""Above 2300 Hz should clamp to 255."""
|
||||
from utils.wefax import _freq_to_pixel
|
||||
|
||||
assert _freq_to_pixel(3000.0) == 255
|
||||
|
||||
def test_ioc_576_pixel_count(self):
|
||||
@@ -196,6 +210,7 @@ class TestWeFaxDecoder:
|
||||
def test_goertzel_mag_detects_tone(self):
|
||||
"""Goertzel should detect a pure tone."""
|
||||
from utils.wefax import _goertzel_mag
|
||||
|
||||
sr = 22050
|
||||
freq = 1900.0
|
||||
t = np.arange(sr) / sr
|
||||
@@ -207,6 +222,7 @@ class TestWeFaxDecoder:
|
||||
def test_goertzel_mag_rejects_wrong_freq(self):
|
||||
"""Goertzel should be much weaker for non-matching frequency."""
|
||||
from utils.wefax import _goertzel_mag
|
||||
|
||||
sr = 22050
|
||||
t = np.arange(sr) / sr
|
||||
samples = np.sin(2 * np.pi * 1900.0 * t)
|
||||
@@ -217,6 +233,7 @@ class TestWeFaxDecoder:
|
||||
def test_detect_tone_start(self):
|
||||
"""detect_tone should identify a 300 Hz start tone."""
|
||||
from utils.wefax import _detect_tone
|
||||
|
||||
sr = 22050
|
||||
t = np.arange(sr) / sr
|
||||
samples = np.sin(2 * np.pi * 300.0 * t)
|
||||
@@ -227,10 +244,11 @@ class TestWeFaxDecoder:
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from utils.wefax import WeFaxImage
|
||||
|
||||
img = WeFaxImage(
|
||||
filename='test.png',
|
||||
path=Path('/tmp/test.png'),
|
||||
station='NOJ',
|
||||
filename="test.png",
|
||||
path=Path("/tmp/test.png"),
|
||||
station="NOJ",
|
||||
frequency_khz=4298,
|
||||
timestamp=datetime(2026, 1, 1, tzinfo=timezone.utc),
|
||||
ioc=576,
|
||||
@@ -238,36 +256,39 @@ class TestWeFaxDecoder:
|
||||
size_bytes=1234,
|
||||
)
|
||||
d = img.to_dict()
|
||||
assert d['filename'] == 'test.png'
|
||||
assert d['station'] == 'NOJ'
|
||||
assert d['frequency_khz'] == 4298
|
||||
assert d['ioc'] == 576
|
||||
assert d['url'] == '/wefax/images/test.png'
|
||||
assert d["filename"] == "test.png"
|
||||
assert d["station"] == "NOJ"
|
||||
assert d["frequency_khz"] == 4298
|
||||
assert d["ioc"] == 576
|
||||
assert d["url"] == "/wefax/images/test.png"
|
||||
|
||||
def test_wefax_progress_to_dict(self):
|
||||
"""WeFaxProgress.to_dict() should produce expected format."""
|
||||
from utils.wefax import WeFaxProgress
|
||||
|
||||
p = WeFaxProgress(
|
||||
status='receiving',
|
||||
station='NOJ',
|
||||
message='Receiving: 100 lines',
|
||||
status="receiving",
|
||||
station="NOJ",
|
||||
message="Receiving: 100 lines",
|
||||
progress_percent=50,
|
||||
line_count=100,
|
||||
)
|
||||
d = p.to_dict()
|
||||
assert d['type'] == 'wefax_progress'
|
||||
assert d['status'] == 'receiving'
|
||||
assert d['progress'] == 50
|
||||
assert d['station'] == 'NOJ'
|
||||
assert d['line_count'] == 100
|
||||
assert d["type"] == "wefax_progress"
|
||||
assert d["status"] == "receiving"
|
||||
assert d["progress"] == 50
|
||||
assert d["station"] == "NOJ"
|
||||
assert d["line_count"] == 100
|
||||
|
||||
def test_singleton_returns_same_instance(self, tmp_path):
|
||||
"""get_wefax_decoder() should return a singleton."""
|
||||
from utils.wefax import WeFaxDecoder
|
||||
|
||||
# Use __new__ to avoid __init__ creating dirs
|
||||
d1 = WeFaxDecoder.__new__(WeFaxDecoder)
|
||||
# Test the module-level singleton pattern
|
||||
import utils.wefax as wefax_mod
|
||||
|
||||
original = wefax_mod._decoder
|
||||
try:
|
||||
wefax_mod._decoder = d1
|
||||
@@ -281,6 +302,7 @@ class TestWeFaxDecoder:
|
||||
# Route tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestWeFaxRoutes:
|
||||
"""WeFax route endpoint tests."""
|
||||
|
||||
@@ -291,37 +313,37 @@ class TestWeFaxRoutes:
|
||||
mock_decoder.is_running = False
|
||||
mock_decoder.get_images.return_value = []
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
response = client.get('/wefax/status')
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.get("/wefax/status")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['available'] is True
|
||||
assert data['running'] is False
|
||||
assert data["available"] is True
|
||||
assert data["running"] is False
|
||||
|
||||
def test_stations_list(self, client):
|
||||
"""GET /wefax/stations should return station list."""
|
||||
_login_session(client)
|
||||
response = client.get('/wefax/stations')
|
||||
response = client.get("/wefax/stations")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'ok'
|
||||
assert data['count'] >= 10
|
||||
assert data["status"] == "ok"
|
||||
assert data["count"] >= 10
|
||||
|
||||
def test_station_detail(self, client):
|
||||
"""GET /wefax/stations/NOJ should return station detail."""
|
||||
_login_session(client)
|
||||
response = client.get('/wefax/stations/NOJ')
|
||||
response = client.get("/wefax/stations/NOJ")
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'ok'
|
||||
assert data['station']['callsign'] == 'NOJ'
|
||||
assert 'current_broadcasts' in data
|
||||
assert data["status"] == "ok"
|
||||
assert data["station"]["callsign"] == "NOJ"
|
||||
assert "current_broadcasts" in data
|
||||
|
||||
def test_station_not_found(self, client):
|
||||
"""GET /wefax/stations/XXXXX should return 404."""
|
||||
_login_session(client)
|
||||
response = client.get('/wefax/stations/XXXXX')
|
||||
response = client.get("/wefax/stations/XXXXX")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_start_requires_frequency(self, client):
|
||||
@@ -330,16 +352,16 @@ class TestWeFaxRoutes:
|
||||
mock_decoder = MagicMock()
|
||||
mock_decoder.is_running = False
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.post(
|
||||
'/wefax/start',
|
||||
"/wefax/start",
|
||||
data=json.dumps({}),
|
||||
content_type='application/json',
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'error'
|
||||
assert data["status"] == "error"
|
||||
|
||||
def test_start_validates_frequency_range(self, client):
|
||||
"""POST /wefax/start with out-of-range frequency should fail."""
|
||||
@@ -347,11 +369,11 @@ class TestWeFaxRoutes:
|
||||
mock_decoder = MagicMock()
|
||||
mock_decoder.is_running = False
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.post(
|
||||
'/wefax/start',
|
||||
data=json.dumps({'frequency_khz': 100}), # 0.1 MHz - too low
|
||||
content_type='application/json',
|
||||
"/wefax/start",
|
||||
data=json.dumps({"frequency_khz": 100}), # 0.1 MHz - too low
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
@@ -362,16 +384,16 @@ class TestWeFaxRoutes:
|
||||
mock_decoder = MagicMock()
|
||||
mock_decoder.is_running = False
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.post(
|
||||
'/wefax/start',
|
||||
data=json.dumps({'frequency_khz': 4298, 'ioc': 999}),
|
||||
content_type='application/json',
|
||||
"/wefax/start",
|
||||
data=json.dumps({"frequency_khz": 4298, "ioc": 999}),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert 'IOC' in data['message']
|
||||
assert "IOC" in data["message"]
|
||||
|
||||
def test_start_validates_lpm(self, client):
|
||||
"""POST /wefax/start with invalid LPM should fail."""
|
||||
@@ -379,16 +401,16 @@ class TestWeFaxRoutes:
|
||||
mock_decoder = MagicMock()
|
||||
mock_decoder.is_running = False
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.post(
|
||||
'/wefax/start',
|
||||
data=json.dumps({'frequency_khz': 4298, 'lpm': 999}),
|
||||
content_type='application/json',
|
||||
"/wefax/start",
|
||||
data=json.dumps({"frequency_khz": 4298, "lpm": 999}),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert 'LPM' in data['message']
|
||||
assert "LPM" in data["message"]
|
||||
|
||||
def test_start_success(self, client):
|
||||
"""POST /wefax/start with valid params should succeed."""
|
||||
@@ -397,31 +419,35 @@ class TestWeFaxRoutes:
|
||||
mock_decoder.is_running = False
|
||||
mock_decoder.start.return_value = True
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder), \
|
||||
patch('routes.wefax.app_module.claim_sdr_device', return_value=None):
|
||||
with (
|
||||
patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder),
|
||||
patch("routes.wefax.app_module.claim_sdr_device", return_value=None),
|
||||
):
|
||||
response = client.post(
|
||||
'/wefax/start',
|
||||
data=json.dumps({
|
||||
'frequency_khz': 4298,
|
||||
'station': 'NOJ',
|
||||
'device': 0,
|
||||
'ioc': 576,
|
||||
'lpm': 120,
|
||||
}),
|
||||
content_type='application/json',
|
||||
"/wefax/start",
|
||||
data=json.dumps(
|
||||
{
|
||||
"frequency_khz": 4298,
|
||||
"station": "NOJ",
|
||||
"device": 0,
|
||||
"ioc": 576,
|
||||
"lpm": 120,
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'started'
|
||||
assert data['frequency_khz'] == 4298
|
||||
assert data['usb_offset_applied'] is True
|
||||
assert math.isclose(data['tuned_frequency_khz'], 4296.1, abs_tol=1e-6)
|
||||
assert data['frequency_reference'] == 'carrier'
|
||||
assert data['station'] == 'NOJ'
|
||||
assert data["status"] == "started"
|
||||
assert data["frequency_khz"] == 4298
|
||||
assert data["usb_offset_applied"] is True
|
||||
assert math.isclose(data["tuned_frequency_khz"], 4296.1, abs_tol=1e-6)
|
||||
assert data["frequency_reference"] == "carrier"
|
||||
assert data["station"] == "NOJ"
|
||||
mock_decoder.start.assert_called_once()
|
||||
start_kwargs = mock_decoder.start.call_args.kwargs
|
||||
assert math.isclose(start_kwargs['frequency_khz'], 4296.1, abs_tol=1e-6)
|
||||
assert math.isclose(start_kwargs["frequency_khz"], 4296.1, abs_tol=1e-6)
|
||||
|
||||
def test_start_respects_dial_reference_override(self, client):
|
||||
"""POST /wefax/start with dial reference should not apply USB offset."""
|
||||
@@ -430,27 +456,31 @@ class TestWeFaxRoutes:
|
||||
mock_decoder.is_running = False
|
||||
mock_decoder.start.return_value = True
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder), \
|
||||
patch('routes.wefax.app_module.claim_sdr_device', return_value=None):
|
||||
with (
|
||||
patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder),
|
||||
patch("routes.wefax.app_module.claim_sdr_device", return_value=None),
|
||||
):
|
||||
response = client.post(
|
||||
'/wefax/start',
|
||||
data=json.dumps({
|
||||
'frequency_khz': 4298,
|
||||
'station': 'NOJ',
|
||||
'device': 0,
|
||||
'frequency_reference': 'dial',
|
||||
}),
|
||||
content_type='application/json',
|
||||
"/wefax/start",
|
||||
data=json.dumps(
|
||||
{
|
||||
"frequency_khz": 4298,
|
||||
"station": "NOJ",
|
||||
"device": 0,
|
||||
"frequency_reference": "dial",
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'started'
|
||||
assert data['usb_offset_applied'] is False
|
||||
assert math.isclose(data['tuned_frequency_khz'], 4298.0, abs_tol=1e-6)
|
||||
assert data['frequency_reference'] == 'dial'
|
||||
assert data["status"] == "started"
|
||||
assert data["usb_offset_applied"] is False
|
||||
assert math.isclose(data["tuned_frequency_khz"], 4298.0, abs_tol=1e-6)
|
||||
assert data["frequency_reference"] == "dial"
|
||||
start_kwargs = mock_decoder.start.call_args.kwargs
|
||||
assert math.isclose(start_kwargs['frequency_khz'], 4298.0, abs_tol=1e-6)
|
||||
assert math.isclose(start_kwargs["frequency_khz"], 4298.0, abs_tol=1e-6)
|
||||
|
||||
def test_start_device_busy(self, client):
|
||||
"""POST /wefax/start should return 409 when device is busy."""
|
||||
@@ -458,30 +488,31 @@ class TestWeFaxRoutes:
|
||||
mock_decoder = MagicMock()
|
||||
mock_decoder.is_running = False
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder), \
|
||||
patch('routes.wefax.app_module.claim_sdr_device',
|
||||
return_value='Device 0 in use by pager'):
|
||||
with (
|
||||
patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder),
|
||||
patch("routes.wefax.app_module.claim_sdr_device", return_value="Device 0 in use by pager"),
|
||||
):
|
||||
response = client.post(
|
||||
'/wefax/start',
|
||||
data=json.dumps({'frequency_khz': 4298}),
|
||||
content_type='application/json',
|
||||
"/wefax/start",
|
||||
data=json.dumps({"frequency_khz": 4298}),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 409
|
||||
data = response.get_json()
|
||||
assert data['error_type'] == 'DEVICE_BUSY'
|
||||
assert data["error_type"] == "DEVICE_BUSY"
|
||||
|
||||
def test_stop(self, client):
|
||||
"""POST /wefax/stop should stop the decoder."""
|
||||
_login_session(client)
|
||||
mock_decoder = MagicMock()
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
response = client.post('/wefax/stop')
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.post("/wefax/stop")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'stopped'
|
||||
assert data["status"] == "stopped"
|
||||
mock_decoder.stop.assert_called_once()
|
||||
|
||||
def test_images_list(self, client):
|
||||
@@ -490,22 +521,22 @@ class TestWeFaxRoutes:
|
||||
mock_decoder = MagicMock()
|
||||
mock_decoder.get_images.return_value = []
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
response = client.get('/wefax/images')
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.get("/wefax/images")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'ok'
|
||||
assert data['count'] == 0
|
||||
assert data["status"] == "ok"
|
||||
assert data["count"] == 0
|
||||
|
||||
def test_delete_image_invalid_filename(self, client):
|
||||
"""DELETE /wefax/images/<filename> should reject invalid filenames."""
|
||||
_login_session(client)
|
||||
mock_decoder = MagicMock()
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
# Use a filename with special chars that won't be split by Flask routing
|
||||
response = client.delete('/wefax/images/te$t!file.png')
|
||||
response = client.delete("/wefax/images/te$t!file.png")
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
@@ -514,8 +545,8 @@ class TestWeFaxRoutes:
|
||||
_login_session(client)
|
||||
mock_decoder = MagicMock()
|
||||
|
||||
with patch('routes.wefax.get_wefax_decoder', return_value=mock_decoder):
|
||||
response = client.delete('/wefax/images/test.jpg')
|
||||
with patch("routes.wefax.get_wefax_decoder", return_value=mock_decoder):
|
||||
response = client.delete("/wefax/images/test.jpg")
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
@@ -524,29 +555,31 @@ class TestWeFaxRoutes:
|
||||
_login_session(client)
|
||||
mock_scheduler = MagicMock()
|
||||
mock_scheduler.enable.return_value = {
|
||||
'enabled': True,
|
||||
'scheduled_count': 2,
|
||||
'total_broadcasts': 2,
|
||||
"enabled": True,
|
||||
"scheduled_count": 2,
|
||||
"total_broadcasts": 2,
|
||||
}
|
||||
|
||||
with patch('utils.wefax_scheduler.get_wefax_scheduler', return_value=mock_scheduler):
|
||||
with patch("utils.wefax_scheduler.get_wefax_scheduler", return_value=mock_scheduler):
|
||||
response = client.post(
|
||||
'/wefax/schedule/enable',
|
||||
data=json.dumps({
|
||||
'station': 'NOJ',
|
||||
'frequency_khz': 4298,
|
||||
'device': 0,
|
||||
}),
|
||||
content_type='application/json',
|
||||
"/wefax/schedule/enable",
|
||||
data=json.dumps(
|
||||
{
|
||||
"station": "NOJ",
|
||||
"frequency_khz": 4298,
|
||||
"device": 0,
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['status'] == 'ok'
|
||||
assert data['usb_offset_applied'] is True
|
||||
assert math.isclose(data['tuned_frequency_khz'], 4296.1, abs_tol=1e-6)
|
||||
assert data["status"] == "ok"
|
||||
assert data["usb_offset_applied"] is True
|
||||
assert math.isclose(data["tuned_frequency_khz"], 4296.1, abs_tol=1e-6)
|
||||
enable_kwargs = mock_scheduler.enable.call_args.kwargs
|
||||
assert math.isclose(enable_kwargs['frequency_khz'], 4296.1, abs_tol=1e-6)
|
||||
assert math.isclose(enable_kwargs["frequency_khz"], 4296.1, abs_tol=1e-6)
|
||||
|
||||
|
||||
class TestWeFaxProgressCallback:
|
||||
@@ -559,14 +592,16 @@ class TestWeFaxProgressCallback:
|
||||
original_device = wefax_routes.wefax_active_device
|
||||
try:
|
||||
wefax_routes.wefax_active_device = 3
|
||||
with patch('routes.wefax.app_module.release_sdr_device') as mock_release:
|
||||
wefax_routes._progress_callback({
|
||||
'type': 'wefax_progress',
|
||||
'status': 'error',
|
||||
'message': 'decode failed',
|
||||
})
|
||||
with patch("routes.wefax.app_module.release_sdr_device") as mock_release:
|
||||
wefax_routes._progress_callback(
|
||||
{
|
||||
"type": "wefax_progress",
|
||||
"status": "error",
|
||||
"message": "decode failed",
|
||||
}
|
||||
)
|
||||
|
||||
mock_release.assert_called_once_with(3, 'rtlsdr')
|
||||
mock_release.assert_called_once_with(3, "rtlsdr")
|
||||
assert wefax_routes.wefax_active_device is None
|
||||
finally:
|
||||
wefax_routes.wefax_active_device = original_device
|
||||
@@ -578,12 +613,14 @@ class TestWeFaxProgressCallback:
|
||||
original_device = wefax_routes.wefax_active_device
|
||||
try:
|
||||
wefax_routes.wefax_active_device = 4
|
||||
with patch('routes.wefax.app_module.release_sdr_device') as mock_release:
|
||||
wefax_routes._progress_callback({
|
||||
'type': 'wefax_progress',
|
||||
'status': 'receiving',
|
||||
'line_count': 120,
|
||||
})
|
||||
with patch("routes.wefax.app_module.release_sdr_device") as mock_release:
|
||||
wefax_routes._progress_callback(
|
||||
{
|
||||
"type": "wefax_progress",
|
||||
"status": "receiving",
|
||||
"line_count": 120,
|
||||
}
|
||||
)
|
||||
|
||||
mock_release.assert_not_called()
|
||||
assert wefax_routes.wefax_active_device == 4
|
||||
|
||||
Reference in New Issue
Block a user