Skip to content

Commit

Permalink
update and add new unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
clavedeluna committed Nov 23, 2023
1 parent 9083c6d commit c08c555
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self, dependency_store: PackageStore, parent_directory: Path):

@abstractmethod
def write(
self, dependencies: list[Requirement], dry_run: bool = False
self, dependencies: list[Dependency], dry_run: bool = False
) -> Optional[ChangeSet]:
pass

Expand Down
16 changes: 8 additions & 8 deletions src/codemodder/dependency_management/requirements_txt_writer.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
from typing import Optional
from codemodder.dependency_management.base_dependency_writer import DependencyWriter
from codemodder.change import Action, Change, ChangeSet, PackageAction, Result
from packaging.requirements import Requirement
from codemodder.diff import create_diff
from codemodder.dependency import Dependency
from packaging.requirements import Requirement


class RequirementsTxtWriter(DependencyWriter):
def write(
self, dependencies: list[Requirement], dry_run: bool = False
self, dependencies: list[Dependency], dry_run: bool = False
) -> Optional[ChangeSet]:
new_dependencies = self.add(dependencies)
if new_dependencies:
return self.add_to_file(new_dependencies, dry_run)
return None

def add_to_file(self, dependencies: list[Requirement], dry_run: bool):
original_lines = self._parse_file()
updated_lines = original_lines.copy()
lines = self._parse_file()
original_lines = lines.copy()
if not original_lines[-1].endswith("\n"):
updated_lines[-1] += "\n"
original_lines[-1] += "\n"

requirement_lines = [f"{dep.requirement}\n" for dep in dependencies]
updated_lines += requirement_lines
updated_lines = original_lines + requirement_lines

diff = create_diff(original_lines, updated_lines)

Expand All @@ -43,8 +44,7 @@ def add_to_file(self, dependencies: list[Requirement], dry_run: bool):

if not dry_run:
with open(self.path, "w", encoding="utf-8") as f:
f.writelines(original_lines)
f.writelines(requirement_lines)
f.writelines(updated_lines)

return ChangeSet(
str(self.path.relative_to(self.parent_directory)),
Expand Down
120 changes: 19 additions & 101 deletions tests/dependency_management/test_dependency_manager.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from pathlib import Path

import pytest

from codemodder.change import ChangeSet
from codemodder.dependency import DefusedXML, Security
from codemodder.dependency_management import DependencyManager, Requirement
from codemodder.dependency_management import DependencyManager
from codemodder.project_analysis.file_parsers import RequirementsTxtParser
from codemodder.project_analysis.file_parsers.package_store import PackageStore


@pytest.fixture(autouse=True, scope="module")
Expand All @@ -12,106 +13,23 @@ def disable_write_dependencies():


class TestDependencyManager:
TEST_DIR = "tests/"

def test_read_dependency_file(self, tmpdir):
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text("requests\n", encoding="utf-8")

dm = DependencyManager(Path(tmpdir))
assert dm.dependencies == {"requests": Requirement("requests")}

@pytest.mark.parametrize("dry_run", [True, False])
def test_add_dependency_preserve_comments(self, tmpdir, dry_run):
contents = "# comment\n\nrequests\n"
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text(contents, encoding="utf-8")

dm = DependencyManager(Path(tmpdir))
dm.add([DefusedXML])
changeset = dm.write(dry_run=dry_run)

assert dependency_file.read_text(encoding="utf-8") == (
contents if dry_run else "# comment\n\nrequests\ndefusedxml~=0.7.1\n"
)

assert changeset is not None
assert changeset.path == dependency_file.name
assert changeset.diff == (
"--- \n"
"+++ \n"
"@@ -1,3 +1,4 @@\n"
" # comment\n"
" \n"
" requests\n"
"+defusedxml~=0.7.1\n"
)
assert len(changeset.changes) == 1
assert changeset.changes[0].lineNumber == 4
assert changeset.changes[0].description == DefusedXML.build_description()
assert changeset.changes[0].properties == {
"contextual_description": True,
"contextual_description_position": "right",
}

def test_add_multiple_dependencies(self, tmpdir):
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text("requests\n", encoding="utf-8")

for dep in [DefusedXML, Security]:
dm = DependencyManager(Path(tmpdir))
dm.add([dep])
dm.write()

assert dependency_file.read_text(encoding="utf-8") == (
"requests\ndefusedxml~=0.7.1\nsecurity~=1.2.0\n"
)

def test_add_same_dependency_only_once(self, tmpdir):
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text("requests\n", encoding="utf-8")

for dep in [Security, Security]:
dm = DependencyManager(Path(tmpdir))
dm.add([dep])
dm.write()

assert dependency_file.read_text(encoding="utf-8") == (
"requests\nsecurity~=1.2.0\n"
def test_cant_write_unknown_store(self, tmpdir):
store = PackageStore(
type="unknown", file="idk.txt", dependencies=[], py_versions=[]
)

@pytest.mark.parametrize("version", ["1.2.0", "1.0.1"])
def test_dont_add_existing_dependency(self, version, tmpdir):
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text(f"requests\nsecurity~={version}\n", encoding="utf-8")
dm = DependencyManager(store, tmpdir)
dependencies = [DefusedXML, Security]

dm = DependencyManager(Path(tmpdir))
dm.add([Security])
dm.write()
changeset = dm.write(dependencies)
assert changeset is None

assert dependency_file.read_text(encoding="utf-8") == (
f"requests\nsecurity~={version}\n"
)
def test_write_for_requirements_txt(self, pkg_with_reqs_txt):
parser = RequirementsTxtParser(pkg_with_reqs_txt)
stores = parser.parse()
assert len(stores) == 1
dm = DependencyManager(stores[0], pkg_with_reqs_txt)
dependencies = [DefusedXML, Security]

def test_dependency_file_no_terminating_newline(self, tmpdir):
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text("requests\nwhatever", encoding="utf-8")

dm = DependencyManager(Path(tmpdir))
dm.add([Security])
changeset = dm.write()

assert changeset is not None
assert changeset.diff == (
"--- \n"
"+++ \n"
"@@ -1,2 +1,3 @@\n"
" requests\n"
"-whatever\n"
"+whatever\n"
"+security~=1.2.0\n"
)

assert dependency_file.read_text(encoding="utf-8") == (
"requests\nwhatever\nsecurity~=1.2.0\n"
)
changeset = dm.write(dependencies)
assert isinstance(changeset, ChangeSet)
132 changes: 132 additions & 0 deletions tests/dependency_management/test_requirements_txt_writer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import pytest
from pathlib import Path
from codemodder.dependency_management.requirements_txt_writer import (
RequirementsTxtWriter,
)
from codemodder.project_analysis.file_parsers.package_store import PackageStore
from codemodder.dependency import DefusedXML, Security


@pytest.fixture(autouse=True, scope="module")
def disable_write_dependencies():
"""Override fixture from conftest.py in order to allow testing"""


class TestRequirementsTxtWriter:
@pytest.mark.parametrize("dry_run", [True, False])
def test_add_dependencies_preserve_comments(self, tmpdir, dry_run):
contents = "# comment\n\nrequests\n"
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text(contents, encoding="utf-8")
store = PackageStore(
type="requirements.txt",
file=str(dependency_file),
dependencies=[],
py_versions=[],
)
writer = RequirementsTxtWriter(store, Path(tmpdir))
dependencies = [DefusedXML, Security]
changeset = writer.write(dependencies, dry_run=dry_run)

assert dependency_file.read_text(encoding="utf-8") == (
contents
if dry_run
else "# comment\n\nrequests\ndefusedxml~=0.7.1\nsecurity~=1.2.0\n"
)

assert changeset is not None
assert changeset.path == dependency_file.name
assert changeset.diff == (
"--- \n"
"+++ \n"
"@@ -1,3 +1,5 @@\n"
" # comment\n"
" \n"
" requests\n"
"+defusedxml~=0.7.1\n"
"+security~=1.2.0\n"
)
assert len(changeset.changes) == 2
change_one = changeset.changes[0]
assert change_one.lineNumber == 4
assert change_one.description == DefusedXML.build_description()
assert change_one.properties == {
"contextual_description": True,
"contextual_description_position": "right",
}
change_two = changeset.changes[1]
assert change_two.lineNumber == 5
assert change_two.description == Security.build_description()
assert change_two.properties == {
"contextual_description": True,
"contextual_description_position": "right",
}

def test_add_same_dependency_only_once(self, tmpdir):
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text("requests\n", encoding="utf-8")

store = PackageStore(
type="requirements.txt",
file=str(dependency_file),
dependencies=[],
py_versions=[],
)
writer = RequirementsTxtWriter(store, Path(tmpdir))
dependencies = [Security, Security]
changeset = writer.write(dependencies)
assert len(changeset.changes) == 1

assert dependency_file.read_text(encoding="utf-8") == (
"requests\nsecurity~=1.2.0\n"
)

def test_dont_add_existing_dependency(self, tmpdir):
dependency_file = Path(tmpdir) / "requirements.txt"
contents = f"requests\nsecurity~=1.2.0\n"
dependency_file.write_text(contents, encoding="utf-8")

store = PackageStore(
type="requirements.txt",
file=str(dependency_file),
dependencies=[Security.requirement],
py_versions=[],
)
writer = RequirementsTxtWriter(store, Path(tmpdir))
dependencies = [Security]
changeset = writer.write(dependencies)
assert changeset is None
assert dependency_file.read_text(encoding="utf-8") == contents

def test_dependency_file_no_terminating_newline(self, tmpdir):
contents = "# comment\n\nrequests"
dependency_file = Path(tmpdir) / "requirements.txt"
dependency_file.write_text(contents, encoding="utf-8")

store = PackageStore(
type="requirements.txt",
file=str(dependency_file),
dependencies=[],
py_versions=[],
)
writer = RequirementsTxtWriter(store, Path(tmpdir))
dependencies = [DefusedXML, Security]
changeset = writer.write(dependencies)

assert (
dependency_file.read_text(encoding="utf-8")
== "# comment\n\nrequests\ndefusedxml~=0.7.1\nsecurity~=1.2.0\n"
)

assert changeset is not None
assert changeset.path == dependency_file.name
assert changeset.diff == (
"--- \n"
"+++ \n"
"@@ -1,3 +1,5 @@\n"
" # comment\n"
" \n"
" requests\n"
"+defusedxml~=0.7.1\n"
"+security~=1.2.0\n"
)

0 comments on commit c08c555

Please sign in to comment.