"""Discovery tests (opc/discovery.py). Pure tests run on any OS; the registry/COM scans are Windows-only and skip elsewhere (IMPLEMENTATION_PLAN §9: COM adapters are import-guarded). """ import sys import pytest from opcda_diagnozer.opc.base import OpcError from opcda_diagnozer.opc.discovery import ( DA_CATEGORIES, ServerInfo, list_servers, normalize_string_array, ) @pytest.mark.parametrize( ("raw", "expected"), [ (None, []), ("", []), ("One.Server.1", ["One.Server.1"]), (("A.Sim.1", "A.Sim.2"), ["A.Sim.1", "A.Sim.2"]), (("A.Sim.1", " A.Sim.1 ", "A.Sim.2"), ["A.Sim.1", "A.Sim.2"]), # dedupe + trim ((1, None, "A.Sim.1"), ["A.Sim.1"]), # non-strings dropped ([], []), ], ) def test_normalize_string_array(raw: object, expected: list[str]) -> None: assert normalize_string_array(raw) == expected def test_registry_source_rejects_remote_host() -> None: with pytest.raises(OpcError, match="local"): list_servers(host="REMOTE-HOST", source="registry") def test_unknown_source_rejected() -> None: with pytest.raises(ValueError, match="unknown source"): list_servers(source="nonsense") # type: ignore[arg-type] @pytest.mark.skipif(sys.platform != "win32", reason="winreg scan is Windows-only") def test_registry_scan_local_structural() -> None: servers = list_servers(source="registry") assert isinstance(servers, list) for server in servers: assert server.source == "registry" assert server.prog_id # non-empty ProgID (or CLSID fallback) assert server.clsid is not None assert server.clsid.startswith("{") and server.clsid.endswith("}") assert set(server.da_versions) <= set(DA_CATEGORIES.values()) assert [s.prog_id.lower() for s in servers] == sorted(s.prog_id.lower() for s in servers) @pytest.mark.skipif(sys.platform != "win32", reason="COM enumeration needs Windows + pywin32") def test_automation_enumeration_smoke() -> None: """Live smoke test — requires a registered Automation Wrapper (dev box).""" try: servers = list_servers(source="automation") except OpcError as exc: pytest.skip(f"Automation Wrapper not usable on this machine: {exc}") assert all(s.source == "automation" and s.prog_id for s in servers)