aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hydrilla_builder/build.py10
-rw-r--r--src/test/test_hydrilla_builder.py146
2 files changed, 120 insertions, 36 deletions
diff --git a/src/hydrilla_builder/build.py b/src/hydrilla_builder/build.py
index e7c6962..652e537 100644
--- a/src/hydrilla_builder/build.py
+++ b/src/hydrilla_builder/build.py
@@ -164,12 +164,12 @@ def generate_spdx_report(root):
mocked_output = FileBuffer()
if reuse_main(args=['--root', str(root), 'lint'], out=mocked_output) != 0:
- stderr.write(mocked_out.get_bytes())
+ stderr.write(mocked_output.get_bytes().decode())
raise ReuseError('Attempt to generate an SPDX report for a REUSE-incompliant package.')
mocked_output = FileBuffer()
if reuse_main(args=['--root', str(root), 'spdx'], out=mocked_output) != 0:
- stderr.write(mocked_out.get_bytes())
+ stderr.write(mocked_output.get_bytes().decode())
raise ReuseError("Couldn't generate an SPDX report for package.")
return mocked_output.get_bytes()
@@ -249,10 +249,10 @@ class Build:
path = path.resolve()
if not path.is_relative_to(self.srcdir):
- raise FileReferenceException(f"Attempt to load '{filename}' which lies outside package source directory.")
+ raise FileReferenceError(f"Attempt to load '{filename}' which lies outside package source directory.")
- if path == self.index_json_path:
- raise FileReferenceException("Attempt to load 'index.json' which is a reserved filename.")
+ if str(path.relative_to(self.srcdir)) == 'index.json':
+ raise FileReferenceError("Attempt to load 'index.json' which is a reserved filename.")
file_ref = self.files_by_path.get(path)
if file_ref is None:
diff --git a/src/test/test_hydrilla_builder.py b/src/test/test_hydrilla_builder.py
index b2f19f0..f4a4d2f 100644
--- a/src/test/test_hydrilla_builder.py
+++ b/src/test/test_hydrilla_builder.py
@@ -6,11 +6,17 @@
import pytest
import json
+import shutil
from tempfile import TemporaryDirectory
from pathlib import Path
from hashlib import sha256, sha1
from zipfile import ZipFile
+from typing import Callable, Optional
+
+from jsonschema import ValidationError
+
+from hydrilla_builder import build
here = Path(__file__).resolve().parent
@@ -164,6 +170,45 @@ class CaseSettings:
self.expected_source_description
]
+ModifyCb = Callable[[CaseSettings, dict], Optional[str]]
+
+def prepare_modified(tmpdir: Path, modify_cb: ModifyCb) -> CaseSettings:
+ """
+ Use sample source package directory with an alternative, modified
+ index.json.
+ """
+ settings = CaseSettings()
+
+ for fn in settings.src_filenames:
+ copy_path = tmpdir / 'srcdir_copy' / fn
+ copy_path.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copy(settings.srcdir / fn, copy_path)
+
+ settings.srcdir = tmpdir / 'srcdir_copy'
+
+ with open(settings.srcdir / 'index.json', 'rt') as file_handle:
+ obj = json.loads(build.strip_json_comments(file_handle.read()))
+
+ contents = modify_cb(settings, obj)
+
+ # Replace the other index.json with new one
+ settings.index_json_path = tmpdir / 'replacement.json'
+
+ if contents is None:
+ contents = json.dumps(obj)
+
+ contents = contents.encode()
+
+ settings.contents['index.json'] = contents
+
+ settings.sha256_hashes['index.json'] = sha256(contents).digest().hex()
+ settings.sha1_hashes['index.json'] = sha1(contents).digest().hex()
+
+ with open(settings.index_json_path, 'wb') as file_handle:
+ file_handle.write(contents)
+
+ return settings
+
@pytest.fixture()
def tmpdir() -> str:
with TemporaryDirectory() as tmpdir:
@@ -173,18 +218,11 @@ def prepare_default(tmpdir: Path) -> CaseSettings:
"""Use sample source package directory as exists in VCS."""
return CaseSettings()
-def prepare_external_index_json(tmpdir: Path) -> dict:
+def modify_index_good(settings: CaseSettings, obj: dict) -> None:
"""
- Use sample source package directory with an alternative, modified
- index.json.
+ Modify index.json object to make a slightly different but *also correct* one
+ that can be used to test some different cases.
"""
- settings = CaseSettings()
-
- from hydrilla_builder.build import strip_json_comments
-
- with open(settings.srcdir / 'index.json', 'rt') as file_handle:
- obj = json.loads(strip_json_comments(file_handle.read()))
-
# Add comments that should be preserved.
for dictionary in (obj, settings.expected_source_description):
dictionary['comment'] = 'index_json comment'
@@ -233,28 +271,12 @@ def prepare_external_index_json(tmpdir: Path) -> dict:
to_process.extend(processed.values())
processed['spurious_property'] = 'some value'
- # Replace the other index.json with new one
- settings.index_json_path = tmpdir / 'replacement.json'
-
- contents = json.dumps(obj).encode()
-
- settings.contents['index.json'] = contents
-
- settings.sha256_hashes['index.json'] = sha256(contents).digest().hex()
- settings.sha1_hashes['index.json'] = sha1(contents).digest().hex()
-
- with open(settings.index_json_path, 'wb') as file_handle:
- file_handle.write(contents)
-
- return settings
-
@pytest.mark.parametrize('prepare_source_example', [
- prepare_default, prepare_external_index_json
+ prepare_default,
+ lambda tmpdir: prepare_modified(tmpdir, modify_index_good)
])
def test_build(tmpdir, prepare_source_example):
"""Build the sample source package and verify the produced files."""
- from hydrilla_builder.build import Build
-
# First, build the package
dstdir = Path(tmpdir) / 'dstdir'
tmpdir = Path(tmpdir) / 'example'
@@ -264,8 +286,8 @@ def test_build(tmpdir, prepare_source_example):
settings = prepare_source_example(tmpdir)
- build = Build(settings.srcdir, settings.index_json_path)
- build.write_package_files(dstdir)
+ build.Build(settings.srcdir, settings.index_json_path)\
+ .write_package_files(dstdir)
# Verify directories under destination directory
assert {'file', 'resource', 'mapping', 'source'} == \
@@ -354,4 +376,66 @@ def test_build(tmpdir, prepare_source_example):
with open(source_dir / 'hello.json', 'rt') as file_handle:
assert json.load(file_handle) == settings.expected_source_description
-# TODO: also check error handling
+def modify_index_missing_file(dummy: CaseSettings, obj: dict) -> None:
+ """
+ Modify index.json to expect missing report.spdx file and cause an error.
+ """
+ del obj['reuse_generate_spdx_report']
+
+def modify_index_schema_error(dummy: CaseSettings, obj: dict) -> None:
+ """Modify index.json to be incompliant with the schema."""
+ del obj['definitions']
+
+def modify_index_bad_comment(dummy: CaseSettings, obj: dict) -> str:
+ """Modify index.json to have an invalid '/' in it."""
+ return json.dumps(obj) + '/something\n'
+
+def modify_index_bad_json(dummy: CaseSettings, obj: dict) -> str:
+ """Modify index.json to not be valid json even after comment stripping."""
+ return json.dumps(obj) + '???/\n'
+
+def modify_index_missing_license(settings: CaseSettings, obj: dict) -> None:
+ """Remove a file to make package REUSE-incompliant."""
+ (settings.srcdir / 'README.txt.license').unlink()
+
+def modify_index_file_outside(dummy: CaseSettings, obj: dict) -> None:
+ """Make index.json illegally reference a file outside srcdir."""
+ obj['copyright'].append({'file': '../abc'})
+
+def modify_index_reference_itself(dummy: CaseSettings, obj: dict) -> None:
+ """Make index.json illegally reference index.json."""
+ obj['copyright'].append({'file': 'index.json'})
+
+def modify_index_report_excluded(dummy: CaseSettings, obj: dict) -> None:
+ """
+ Make index.json require generation of index.json but not include it among
+ copyright files.
+ """
+ obj['copyright'] = [fr for fr in obj['copyright']
+ if fr['file'] != 'report.spdx']
+
+@pytest.mark.parametrize('break_index_json', [
+ (modify_index_missing_file, FileNotFoundError),
+ (modify_index_schema_error, ValidationError),
+ (modify_index_bad_comment, json.JSONDecodeError),
+ (modify_index_bad_json, json.JSONDecodeError),
+ (modify_index_missing_license, build.ReuseError),
+ (modify_index_file_outside, build.FileReferenceError),
+ (modify_index_reference_itself, build.FileReferenceError),
+ (modify_index_report_excluded, build.FileReferenceError)
+])
+def test_build_error(tmpdir: str, break_index_json: tuple[ModifyCb, type]):
+ """Build the sample source package and verify the produced files."""
+ dstdir = Path(tmpdir) / 'dstdir'
+ tmpdir = Path(tmpdir) / 'example'
+
+ dstdir.mkdir(exist_ok=True)
+ tmpdir.mkdir(exist_ok=True)
+
+ modify_cb, error_type = break_index_json
+
+ settings = prepare_modified(tmpdir, modify_cb)
+
+ with pytest.raises(error_type):
+ build.Build(settings.srcdir, settings.index_json_path)\
+ .write_package_files(dstdir)