"""Tests for SAM utility functions.""" import base64 import pytest from i2p_sam.utils import parse_params, negotiate_version, generate_transient_destination class TestParseParams: """Tests for parse_params().""" def test_parse_params(self): """Basic key=value parsing.""" result = parse_params("MIN=3.0 MAX=3.3") assert result == {"MIN": "3.0", "MAX": "3.3"} def test_parse_params_quoted(self): """Quoted values with spaces.""" result = parse_params('ID="my session" STYLE=STREAM') assert result["ID"] == "my session" assert result["STYLE"] == "STREAM" def test_parse_params_empty(self): """Empty string returns empty dict.""" assert parse_params("") == {} def test_parse_params_single(self): """Single key=value pair.""" result = parse_params("RESULT=OK") assert result == {"RESULT": "OK"} def test_parse_params_preserves_case_in_values(self): """Keys are uppercased, values preserve case.""" result = parse_params("style=Stream") assert result["STYLE"] == "Stream" class TestNegotiateVersion: """Tests for negotiate_version().""" def test_negotiate_version_exact(self): """Exact match — client wants exactly 3.3.""" result = negotiate_version("3.3", "3.3", ["3.0", "3.1", "3.2", "3.3"]) assert result == "3.3" def test_negotiate_version_range(self): """Range negotiation — pick highest mutual version.""" result = negotiate_version("3.0", "3.3", ["3.0", "3.1", "3.2", "3.3"]) assert result == "3.3" def test_negotiate_version_range_limited(self): """Server supports fewer versions than client requests.""" result = negotiate_version("3.0", "3.3", ["3.0", "3.1"]) assert result == "3.1" def test_negotiate_version_no_match(self): """No overlap returns None.""" result = negotiate_version("3.4", "3.5", ["3.0", "3.1", "3.2", "3.3"]) assert result is None def test_negotiate_version_client_below(self): """Client max below server min.""" result = negotiate_version("2.0", "2.9", ["3.0", "3.1", "3.2", "3.3"]) assert result is None class TestGenerateTransientDestination: """Tests for generate_transient_destination().""" def test_generate_transient_destination(self): """Produces valid I2P base64 string and non-empty raw bytes.""" raw, b64 = generate_transient_destination() assert isinstance(raw, bytes) assert len(raw) > 0 assert isinstance(b64, str) assert len(b64) > 0 # Verify b64 is decodable using I2P base64 alphabet (-~ instead of +/) padding = 4 - (len(b64) % 4) if padding != 4: b64_padded = b64 + "=" * padding else: b64_padded = b64 decoded = base64.b64decode(b64_padded, altchars=b"-~") assert decoded == raw def test_generate_transient_destination_unique(self): """Each call produces a different destination.""" _, b64_1 = generate_transient_destination() _, b64_2 = generate_transient_destination() assert b64_1 != b64_2