"""Tests for I2PTunnel CLI.""" import sys import tempfile from pathlib import Path from unittest.mock import patch, AsyncMock, MagicMock import pytest from i2p_apps.i2ptunnel.cli import _get_parser, _run_list, _run_add, main class TestParser: def test_start_command(self): parser = _get_parser() args = parser.parse_args(["start", "--sam-port", "7777"]) assert args.command == "start" assert args.sam_port == 7777 def test_list_command(self): parser = _get_parser() args = parser.parse_args(["list"]) assert args.command == "list" def test_add_command(self): parser = _get_parser() args = parser.parse_args([ "add", "--name", "myproxy", "--type", "httpclient", "--port", "4444", "--interface", "0.0.0.0", "--start-on-load" ]) assert args.command == "add" assert args.name == "myproxy" assert args.tunnel_type == "httpclient" assert args.port == 4444 assert args.interface == "0.0.0.0" assert args.start_on_load is True def test_add_defaults(self): parser = _get_parser() args = parser.parse_args(["add", "--name", "t", "--type", "server", "--port", "80"]) assert args.interface == "127.0.0.1" assert args.target == "" assert args.start_on_load is False def test_no_command(self): parser = _get_parser() args = parser.parse_args([]) assert args.command is None def test_start_with_config(self): parser = _get_parser() args = parser.parse_args(["start", "--config", "/tmp/my.config"]) assert args.config == Path("/tmp/my.config") class TestRunList: def test_no_config_file(self, capsys): parser = _get_parser() args = parser.parse_args(["list", "--config", "/nonexistent/path"]) with pytest.raises(SystemExit): _run_list(args) captured = capsys.readouterr() assert "not found" in captured.err def test_lists_tunnels(self, tmp_path, capsys): config = tmp_path / "test.config" config.write_text( "tunnel.0.name=myhttp\n" "tunnel.0.type=httpclient\n" "tunnel.0.listenPort=4444\n" "tunnel.0.interface=127.0.0.1\n" "tunnel.0.startOnLoad=true\n" ) parser = _get_parser() args = parser.parse_args(["list", "--config", str(config)]) _run_list(args) captured = capsys.readouterr() assert "myhttp" in captured.out def test_empty_config(self, tmp_path, capsys): config = tmp_path / "empty.config" config.write_text("") parser = _get_parser() args = parser.parse_args(["list", "--config", str(config)]) _run_list(args) captured = capsys.readouterr() assert "No tunnels" in captured.out class TestRunAdd: def test_add_creates_config(self, tmp_path, capsys): config = tmp_path / "new.config" parser = _get_parser() args = parser.parse_args([ "add", "--config", str(config), "--name", "testserver", "--type", "server", "--port", "8080", "--target", "127.0.0.1" ]) _run_add(args) captured = capsys.readouterr() assert "Added tunnel" in captured.out assert config.exists() def test_add_unknown_type(self, tmp_path): config = tmp_path / "test.config" parser = _get_parser() args = parser.parse_args([ "add", "--config", str(config), "--name", "bad", "--type", "nonexistent", "--port", "80" ]) with pytest.raises(SystemExit): _run_add(args) def test_add_appends_to_existing(self, tmp_path, capsys): config = tmp_path / "existing.config" config.write_text( "tunnel.0.name=first\n" "tunnel.0.type=httpclient\n" "tunnel.0.listenPort=4444\n" "tunnel.0.interface=127.0.0.1\n" ) parser = _get_parser() args = parser.parse_args([ "add", "--config", str(config), "--name", "second", "--type", "httpclient", "--port", "4445" ]) _run_add(args) # Verify both tunnels exist text = config.read_text() assert "first" in text assert "second" in text class TestMain: def test_no_args_prints_help(self): with patch("sys.argv", ["i2p-tunnel"]): with pytest.raises(SystemExit) as exc: main() assert exc.value.code == 1 def test_list_command(self, tmp_path, capsys): config = tmp_path / "t.config" config.write_text("") with patch("sys.argv", ["i2p-tunnel", "list", "--config", str(config)]): main() captured = capsys.readouterr() assert "No tunnels" in captured.out