"""Bencode and UDP packet unit tests.""" from __future__ import annotations import struct import pytest from app.probes.bencode import BencodeError, bdecode, validate_peers_then_discard from app.probes.udp import ( create_announce_request, create_connect_request, parse_announce_response, parse_connect_response, ) def test_bencode_valid_and_invalid(): # d8:intervali1800e5:peers6:\x01\x02\x03\x04\x00Pe peers = b"\x01\x02\x03\x04\x00\x50" payload = b"d8:intervali1800e5:peers6:" + peers + b"e" decoded = bdecode(payload) assert decoded["interval"] == 1800 assert isinstance(decoded["peers"], list) assert validate_peers_then_discard(decoded) is True assert decoded["peers"] is None with pytest.raises(BencodeError): bdecode(b"") with pytest.raises(BencodeError): bdecode(b"i123") # incomplete with pytest.raises(BencodeError): bdecode(b"4:spam") # not a dict root for tracker helper — actually bdecode requires dict # 4:spam is a string root with pytest.raises(BencodeError): bdecode(b"l4:spame") def test_udp_connect_and_announce_roundtrip_fields(): req, tid = create_connect_request() assert len(req) == 16 # forge response conn_id = 0x1122334455667788 resp = struct.pack("!iiq", 0, tid, conn_id) assert parse_connect_response(resp, tid) == conn_id info = b"a" * 20 peer = b"b" * 20 ann, atid = create_announce_request(conn_id, info, peer, num_want=0) assert len(ann) == 98 # announce response: action, tid, interval, leechers, seeders + fake peers aresp = struct.pack("!iiiii", 1, atid, 1800, 2, 5) + b"\x00" * 6 interval, leechers, seeders = parse_announce_response(aresp, atid) assert interval == 1800 assert leechers == 2 assert seeders == 5 def test_udp_transaction_mismatch(): resp = struct.pack("!iiq", 0, 123, 99) with pytest.raises(RuntimeError, match="transaction"): parse_connect_response(resp, 456) aresp = struct.pack("!iiiii", 1, 1, 10, 0, 0) with pytest.raises(RuntimeError, match="transaction"): parse_announce_response(aresp, 2)