249 lines
6.9 KiB
Python
249 lines
6.9 KiB
Python
"""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
|