"""Tests for CLI argument parsing.""" import pytest from s5p import __version__ from s5p.cli import _parse_args class TestDefaults: """Default argument values.""" def test_no_args(self): args = _parse_args([]) assert args.config is None assert args.listen is None assert args.chain is None assert args.timeout is None assert args.retries is None assert args.max_connections is None assert args.verbose is False assert args.quiet is False assert args.proxy_source is None assert args.api is None assert args.cprofile is None assert args.tracemalloc is None class TestFlags: """Flag parsing.""" def test_verbose(self): args = _parse_args(["-v"]) assert args.verbose is True def test_quiet(self): args = _parse_args(["-q"]) assert args.quiet is True def test_config(self): args = _parse_args(["-c", "s5p.yaml"]) assert args.config == "s5p.yaml" def test_config_long(self): args = _parse_args(["--config", "s5p.yaml"]) assert args.config == "s5p.yaml" def test_listen(self): args = _parse_args(["-l", "0.0.0.0:9999"]) assert args.listen == "0.0.0.0:9999" def test_chain(self): args = _parse_args(["-C", "socks5://127.0.0.1:9050"]) assert args.chain == "socks5://127.0.0.1:9050" def test_chain_multi(self): args = _parse_args(["-C", "socks5://a:1080,http://b:8080"]) assert args.chain == "socks5://a:1080,http://b:8080" def test_timeout(self): args = _parse_args(["-t", "30"]) assert args.timeout == 30.0 def test_retries(self): args = _parse_args(["-r", "5"]) assert args.retries == 5 def test_max_connections(self): args = _parse_args(["-m", "512"]) assert args.max_connections == 512 def test_proxy_source(self): args = _parse_args(["-S", "http://api:8081/proxies"]) assert args.proxy_source == "http://api:8081/proxies" def test_api(self): args = _parse_args(["--api", "127.0.0.1:1081"]) assert args.api == "127.0.0.1:1081" def test_cprofile_default(self): args = _parse_args(["--cprofile"]) assert args.cprofile == "s5p.prof" def test_cprofile_custom(self): args = _parse_args(["--cprofile", "out.prof"]) assert args.cprofile == "out.prof" def test_tracemalloc_default(self): args = _parse_args(["--tracemalloc"]) assert args.tracemalloc == 10 def test_tracemalloc_custom(self): args = _parse_args(["--tracemalloc", "20"]) assert args.tracemalloc == 20 class TestVersion: """--version flag.""" def test_version_output(self, capsys): with pytest.raises(SystemExit, match="0"): _parse_args(["--version"]) captured = capsys.readouterr() assert captured.out.strip() == f"s5p {__version__}" def test_version_short(self, capsys): with pytest.raises(SystemExit, match="0"): _parse_args(["-V"]) captured = capsys.readouterr() assert "0.3.0" in captured.out class TestCombinations: """Multiple flags together.""" def test_verbose_with_chain(self): args = _parse_args(["-v", "-C", "socks5://tor:9050"]) assert args.verbose is True assert args.chain == "socks5://tor:9050" def test_config_with_api(self): args = _parse_args(["-c", "s5p.yaml", "--api", "0.0.0.0:1090"]) assert args.config == "s5p.yaml" assert args.api == "0.0.0.0:1090" def test_listen_with_timeout_and_retries(self): args = _parse_args(["-l", ":8080", "-t", "15", "-r", "3"]) assert args.listen == ":8080" assert args.timeout == 15.0 assert args.retries == 3 class TestInvalid: """Invalid argument handling.""" def test_unknown_flag(self): with pytest.raises(SystemExit, match="2"): _parse_args(["--nonexistent"]) def test_timeout_non_numeric(self): with pytest.raises(SystemExit, match="2"): _parse_args(["-t", "abc"]) def test_retries_non_numeric(self): with pytest.raises(SystemExit, match="2"): _parse_args(["-r", "abc"]) def test_max_connections_non_numeric(self): with pytest.raises(SystemExit, match="2"): _parse_args(["-m", "abc"]) def test_tracemalloc_non_numeric(self): with pytest.raises(SystemExit, match="2"): _parse_args(["--tracemalloc", "abc"])