from __future__ import annotations from pathlib import Path import pytest from tests.helpers import StubEcosystemHandler, stub_registry, write_files from vuln_scan.core.dependency_graph import DependencyGraph from vuln_scan.io.workspace_scanner import WorkspaceScanner # -------------------------------------------------------- # Tests # -------------------------------------------------------- @pytest.mark.parametrize( "files, match_substr, project_dir, excluded_fragments, expected_parsed, expected_dep_count", [ pytest.param( {"requirements.txt": "requests==2.0", "src/requirements.txt": "flask==1.0"}, "requirements.txt", None, (), {"requirements.txt", "src/requirements.txt"}, 2, id="finds-manifest-files-recursively", ), pytest.param( { "requirements.txt": "requests==2.0", "venv/requirements.txt": "should-ignore", "node_modules/package.json": "{}", }, "requirements.txt", None, (), {"requirements.txt"}, 1, id="excludes-default-dirs", ), pytest.param( {"root-manifest.txt": "root", "src/app-manifest.txt": "app"}, "manifest", "src", (), {"src/app-manifest.txt"}, 1, id="respects-project-dir", ), pytest.param( { "requirements.txt": "root", "build/requirements.txt": "build", "dist/requirements.txt": "dist", }, "requirements.txt", None, ("build", "dist"), {"requirements.txt"}, 1, id="excludes-config-fragment-dirs", ), pytest.param( {"requirements.txt": "requests==2.0", "Gemfile": "# ruby"}, "requirements.txt", None, (), {"requirements.txt"}, 1, id="skips-unhandled-manifests", ), pytest.param( { "requirements.txt": "root", "requirements-ignored-in-name.txt": "should-exclude", }, "requirements.txt", None, ("-ignored-",), {"requirements.txt"}, 1, id="excludes-config-fragment-in-file-path", ), ], ) def test_scan( tmp_path: Path, files: dict[str, str], match_substr: str, project_dir: str | None, excluded_fragments: tuple[str, ...], expected_parsed: set[str], expected_dep_count: int, ) -> None: write_files(tmp_path, files) handler = StubEcosystemHandler(deps_count=1) result = WorkspaceScanner( base_path=tmp_path, project_dir=project_dir, excluded_path_fragments=excluded_fragments, ).scan(stub_registry(handler, match_substr)) assert isinstance(result, DependencyGraph) assert set(handler.parse_calls) == expected_parsed assert result.dependency_count() == expected_dep_count def test_returns_populated_graph_with_multiple_deps(tmp_path: Path) -> None: write_files(tmp_path, {"requirements.txt": "requests==2.0"}) handler = StubEcosystemHandler(deps_count=3) result = WorkspaceScanner(base_path=tmp_path).scan( stub_registry(handler, "requirements.txt"), ) assert result.dependency_count() == 3 assert result.package_count() == 3