"""Tests for package parsers.""" import tempfile import os from pathlib import Path import pytest from depcheck.models import PackageManager from depcheck.parsers import create_parser_registry from depcheck.parsers.cargo import CargoParser from depcheck.parsers.go import GoParser from depcheck.parsers.npm import NpmParser from depcheck.parsers.pip import PipParser class TestNpmParser: """Tests for NPM package.json parser.""" def test_parse_simple_package_json(self): """Test parsing a simple package.json.""" content = """{ "name": "test-project", "version": "1.0.0", "dependencies": { "express": "4.18.2", "lodash": "4.17.21" } }""" with tempfile.TemporaryDirectory() as tmpdir: pkg_path = Path(tmpdir) / "package.json" pkg_path.write_text(content) parser = NpmParser() deps = parser.parse(pkg_path) assert len(deps) == 2 assert any(d.name == "express" for d in deps) assert any(d.name == "lodash" for d in deps) def test_parse_dev_dependencies(self): """Test parsing devDependencies.""" content = """{ "name": "test-project", "devDependencies": { "jest": "29.7.0", "eslint": "8.56.0" } }""" with tempfile.TemporaryDirectory() as tmpdir: pkg_path = Path(tmpdir) / "package.json" pkg_path.write_text(content) parser = NpmParser() deps = parser.parse(pkg_path) assert len(deps) == 2 assert all(d.category == "devDependencies" for d in deps) def test_parse_optional_dependencies(self): """Test parsing optionalDependencies.""" content = """{ "optionalDependencies": { "fsevents": "2.3.3" } }""" with tempfile.TemporaryDirectory() as tmpdir: pkg_path = Path(tmpdir) / "package.json" pkg_path.write_text(content) parser = NpmParser() deps = parser.parse(pkg_path) assert len(deps) == 1 assert deps[0].category == "optionalDependencies" def test_invalid_json_handled_gracefully(self): """Test that invalid JSON is handled gracefully.""" content = "{ invalid json }" with tempfile.TemporaryDirectory() as tmpdir: pkg_path = Path(tmpdir) / "package.json" pkg_path.write_text(content) parser = NpmParser() deps = parser.parse(pkg_path) assert len(deps) == 0 class TestPipParser: """Tests for pip requirements.txt parser.""" def test_parse_requirements_txt(self): """Test parsing requirements.txt.""" content = """# This is a comment requests>=2.31.0 flask>=2.0.0 numpy==1.24.0 """ with tempfile.TemporaryDirectory() as tmpdir: req_path = Path(tmpdir) / "requirements.txt" req_path.write_text(content) parser = PipParser() deps = parser.parse(req_path) assert len(deps) == 3 assert any(d.name == "requests" for d in deps) assert any(d.name == "flask" for d in deps) assert any(d.name == "numpy" for d in deps) def test_parse_requirements_with_comments(self): """Test that comments are ignored.""" content = """requests==2.31.0 # inline comment flask>=2.0.0; python_version >= \"3.8\" """ with tempfile.TemporaryDirectory() as tmpdir: req_path = Path(tmpdir) / "requirements.txt" req_path.write_text(content) parser = PipParser() deps = parser.parse(req_path) assert len(deps) >= 1 def test_parse_pyproject_toml(self): """Test parsing pyproject.toml.""" content = """ [project] dependencies = [ \"requests>=2.31.0\", \"flask>=2.0.0\" ] """ with tempfile.TemporaryDirectory() as tmpdir: toml_path = Path(tmpdir) / "pyproject.toml" toml_path.write_text(content) parser = PipParser() deps = parser.parse(toml_path) assert len(deps) == 2 class TestGoParser: """Tests for Go go.mod parser.""" def test_parse_go_mod(self): """Test parsing go.mod file.""" content = """ module github.com/example/project go 1.21 require ( github.com/stretchr/testify v1.8.4 golang.org/x/crypto v0.17.0 ) """ with tempfile.TemporaryDirectory() as tmpdir: mod_path = Path(tmpdir) / "go.mod" mod_path.write_text(content) parser = GoParser() deps = parser.parse(mod_path) assert len(deps) == 2 assert any("testify" in d.name for d in deps) assert any("crypto" in d.name for d in deps) class TestCargoParser: """Tests for Rust Cargo.toml parser.""" def test_parse_cargo_toml(self): """Test parsing Cargo.toml file.""" content = """ [package] name = "my-project" version = "0.1.0" edition = "2021" [dependencies] serde = "1.0" tokio = "1.36" [dev-dependencies] proptest = "1.4" """ with tempfile.TemporaryDirectory() as tmpdir: cargo_path = Path(tmpdir) / "Cargo.toml" cargo_path.write_text(content) parser = CargoParser() deps = parser.parse(cargo_path) assert len(deps) == 3 assert any(d.name == "serde" for d in deps) assert any(d.name == "tokio" for d in deps) assert any(d.name == "proptest" for d in deps) class TestParserRegistry: """Tests for parser registry.""" def test_get_parser_for_package_json(self): """Test getting correct parser for package.json.""" registry = create_parser_registry() with tempfile.TemporaryDirectory() as tmpdir: pkg_path = Path(tmpdir) / "package.json" pkg_path.write_text('{"name": "test"}') parser = registry.get_parser(pkg_path) assert parser is not None assert parser.package_manager == PackageManager.NPM def test_get_parser_for_requirements(self): """Test getting correct parser for requirements.txt.""" registry = create_parser_registry() with tempfile.TemporaryDirectory() as tmpdir: req_path = Path(tmpdir) / "requirements.txt" req_path.write_text("requests==2.31.0") parser = registry.get_parser(req_path) assert parser is not None assert parser.package_manager == PackageManager.PIP def test_no_parser_for_unknown_file(self): """Test that unknown file types return None.""" registry = create_parser_registry() with tempfile.TemporaryDirectory() as tmpdir: unknown_path = Path(tmpdir) / "unknown.ext" unknown_path.write_text("some content") parser = registry.get_parser(unknown_path) assert parser is None