from __future__ import annotations from pathlib import Path from sshctl.config.parser import parse_config, parse_file from sshctl.core.exceptions import ParseError def test_parse_empty_config() -> None: config = parse_config("") assert config.blocks == [] assert config.raw_includes == [] def test_parse_single_host() -> None: text = """Host myserver HostName 10.0.0.1 User admin Port 2222 """ config = parse_config(text) assert len(config.blocks) == 1 block = config.blocks[0] assert block.alias == "myserver" assert block.hostname == "10.0.0.1" assert block.user == "admin" assert block.port == 2222 def test_parse_host_star() -> None: text = """Host * User root Port 22 """ config = parse_config(text) assert len(config.blocks) == 1 assert config.blocks[0].alias == "*" assert config.blocks[0].user == "root" def test_parse_multiple_hosts() -> None: text = """Host server1 HostName 10.0.0.1 Host server2 HostName 10.0.0.2 ProxyJump server1 """ config = parse_config(text) assert len(config.blocks) == 2 assert config.blocks[0].alias == "server1" assert config.blocks[1].alias == "server2" assert config.blocks[1].proxy_jump == "server1" def test_parse_includes() -> None: text = """Host * User root Include conf.d/internal/*.conf Include conf.d/98-jumpservers.conf """ config = parse_config(text) assert len(config.raw_includes) == 2 assert "conf.d/internal/*.conf" in config.raw_includes assert "conf.d/98-jumpservers.conf" in config.raw_includes def test_parse_comments_and_blanks() -> None: text = """# This is a comment Host test HostName example.com # indent comment User tester """ config = parse_config(text) assert len(config.blocks) == 1 assert config.blocks[0].alias == "test" def test_parse_file_not_found() -> None: raised = False try: parse_file("/nonexistent/ssh_config") except ParseError: raised = True assert raised, "Expected ParseError" def test_parse_file(sample_config: Path) -> None: config = parse_file(sample_config) assert len(config.blocks) >= 3 assert config.find("server1") is not None assert config.find("server2") is not None def test_parse_quoted_values() -> None: text = """Host test IdentityFile "~/.ssh/keys.d/id_ed25519" ProxyJump 'gw.example.com' """ config = parse_config(text) block = config.blocks[0] assert block.get("IdentityFile") == "~/.ssh/keys.d/id_ed25519" assert block.get("ProxyJump") == "gw.example.com" def test_find_all_wildcard() -> None: text = """Host web01 HostName 10.0.0.1 Host web02 HostName 10.0.0.2 Host db01 HostName 10.0.0.3 """ config = parse_config(text) webs = config.find_all("web*") assert len(webs) == 2 def test_aliases_property() -> None: text = """Host * User root Host server1 HostName 10.0.0.1 Host server2 HostName 10.0.0.2 """ config = parse_config(text) assert config.aliases == ["server1", "server2"]