"""Tests for LeaseSet2, MetaLease, MetaLeaseSet, and OfflineBlock.""" import os import struct import pytest from i2p_data.lease_set2 import LeaseSet2, MetaLease, OfflineBlock class TestMetaLease: def _make(self, **kwargs): defaults = { "gateway_hash": os.urandom(32), "flags": 0, "ls_type": 3, "cost": 0, "end_date": 1700000000, } defaults.update(kwargs) return MetaLease(**defaults) def test_creation(self): gw = os.urandom(32) ml = MetaLease(gateway_hash=gw, flags=0, ls_type=3, cost=5, end_date=1700000000) assert ml.gateway_hash == gw assert ml.flags == 0 assert ml.ls_type == 3 assert ml.cost == 5 assert ml.end_date == 1700000000 def test_default_values(self): gw = os.urandom(32) ml = MetaLease(gateway_hash=gw) assert ml.flags == 0 assert ml.ls_type == 3 assert ml.cost == 0 assert ml.end_date == 0 def test_wrong_hash_length(self): with pytest.raises(ValueError, match="32 bytes"): MetaLease(gateway_hash=b"\x00" * 16) def test_roundtrip(self): ml = self._make() data = ml.to_bytes() assert len(data) == MetaLease.SIZE # 40 ml2 = MetaLease.from_bytes(data) assert ml == ml2 def test_from_bytes_too_short(self): with pytest.raises(ValueError, match="40 bytes"): MetaLease.from_bytes(b"\x00" * 10) def test_to_bytes_format(self): gw = b"\xaa" * 32 ml = MetaLease(gateway_hash=gw, flags=1, ls_type=7, cost=10, end_date=12345) data = ml.to_bytes() assert data[:32] == gw assert struct.unpack("!H", data[32:34])[0] == 1 assert data[34] == 7 assert data[35] == 10 assert struct.unpack("!I", data[36:40])[0] == 12345 def test_equality(self): gw = os.urandom(32) ml1 = MetaLease(gateway_hash=gw, cost=5, end_date=100) ml2 = MetaLease(gateway_hash=gw, cost=5, end_date=100) assert ml1 == ml2 def test_inequality(self): ml1 = self._make(cost=1) ml2 = self._make(cost=2) assert ml1 != ml2 def test_not_equal_to_other_types(self): ml = self._make() assert ml != "not a metalease" def test_hash_consistent(self): gw = os.urandom(32) ml1 = MetaLease(gateway_hash=gw, cost=5, end_date=100) ml2 = MetaLease(gateway_hash=gw, cost=5, end_date=100) assert hash(ml1) == hash(ml2) def test_repr(self): gw = b"\xab\xcd\xef\x01" + os.urandom(28) ml = MetaLease(gateway_hash=gw, ls_type=7, cost=3) r = repr(ml) assert "MetaLease" in r assert "type=7" in r assert "cost=3" in r class TestLeaseSet2Properties: """Test LeaseSet2 property accessors and flags without serialization.""" def test_flags_offline(self): assert LeaseSet2.FLAG_OFFLINE_KEYS == 0x0001 def test_flags_unpublished(self): assert LeaseSet2.FLAG_UNPUBLISHED == 0x0002 def test_flags_blinded(self): assert LeaseSet2.FLAG_BLINDED == 0x0004 def test_type(self): assert LeaseSet2.TYPE == 3 def test_max_leases(self): assert LeaseSet2.MAX_LEASES == 16 def test_max_enc_keys(self): assert LeaseSet2.MAX_ENC_KEYS == 8 class TestOfflineBlock: def test_to_bytes_roundtrip_structure(self): """Test that OfflineBlock.to_bytes() produces correct wire format structure.""" from unittest.mock import MagicMock sig_type = MagicMock() sig_type.code = 7 ob = OfflineBlock( transient_expires=1700000000, transient_sig_type=sig_type, transient_spk=b"\x11" * 32, offline_signature=b"\x22" * 64, ) data = ob.to_bytes() # 4 (expires) + 2 (sig type code) + 32 (spk) + 64 (sig) assert len(data) == 4 + 2 + 32 + 64 assert struct.unpack("!I", data[:4])[0] == 1700000000 assert struct.unpack("!H", data[4:6])[0] == 7 assert data[6:38] == b"\x11" * 32 assert data[38:] == b"\x22" * 64