Project

General

Profile

« Previous | Next » 

Revision b5eb89e1

Added by koszko over 1 year ago

test&fix error handling

View differences:

src/hydrilla_builder/build.py
164 164

  
165 165
    mocked_output = FileBuffer()
166 166
    if reuse_main(args=['--root', str(root), 'lint'], out=mocked_output) != 0:
167
        stderr.write(mocked_out.get_bytes())
167
        stderr.write(mocked_output.get_bytes().decode())
168 168
        raise ReuseError('Attempt to generate an SPDX report for a REUSE-incompliant package.')
169 169

  
170 170
    mocked_output = FileBuffer()
171 171
    if reuse_main(args=['--root', str(root), 'spdx'], out=mocked_output) != 0:
172
        stderr.write(mocked_out.get_bytes())
172
        stderr.write(mocked_output.get_bytes().decode())
173 173
        raise ReuseError("Couldn't generate an SPDX report for package.")
174 174

  
175 175
    return mocked_output.get_bytes()
......
249 249

  
250 250
        path = path.resolve()
251 251
        if not path.is_relative_to(self.srcdir):
252
            raise FileReferenceException(f"Attempt to load '{filename}' which lies outside package source directory.")
252
            raise FileReferenceError(f"Attempt to load '{filename}' which lies outside package source directory.")
253 253

  
254
        if path == self.index_json_path:
255
            raise FileReferenceException("Attempt to load 'index.json' which is a reserved filename.")
254
        if str(path.relative_to(self.srcdir)) == 'index.json':
255
            raise FileReferenceError("Attempt to load 'index.json' which is a reserved filename.")
256 256

  
257 257
        file_ref = self.files_by_path.get(path)
258 258
        if file_ref is None:
src/test/test_hydrilla_builder.py
6 6

  
7 7
import pytest
8 8
import json
9
import shutil
9 10

  
10 11
from tempfile import TemporaryDirectory
11 12
from pathlib import Path
12 13
from hashlib import sha256, sha1
13 14
from zipfile import ZipFile
15
from typing import Callable, Optional
16

  
17
from jsonschema import ValidationError
18

  
19
from hydrilla_builder import build
14 20

  
15 21
here = Path(__file__).resolve().parent
16 22

  
......
164 170
            self.expected_source_description
165 171
        ]
166 172

  
173
ModifyCb = Callable[[CaseSettings, dict], Optional[str]]
174

  
175
def prepare_modified(tmpdir: Path, modify_cb: ModifyCb) -> CaseSettings:
176
    """
177
    Use sample source package directory with an alternative, modified
178
    index.json.
179
    """
180
    settings = CaseSettings()
181

  
182
    for fn in settings.src_filenames:
183
        copy_path = tmpdir / 'srcdir_copy' / fn
184
        copy_path.parent.mkdir(parents=True, exist_ok=True)
185
        shutil.copy(settings.srcdir / fn, copy_path)
186

  
187
    settings.srcdir = tmpdir / 'srcdir_copy'
188

  
189
    with open(settings.srcdir / 'index.json', 'rt') as file_handle:
190
        obj = json.loads(build.strip_json_comments(file_handle.read()))
191

  
192
    contents = modify_cb(settings, obj)
193

  
194
    # Replace the other index.json with new one
195
    settings.index_json_path = tmpdir / 'replacement.json'
196

  
197
    if contents is None:
198
        contents = json.dumps(obj)
199

  
200
    contents = contents.encode()
201

  
202
    settings.contents['index.json'] = contents
203

  
204
    settings.sha256_hashes['index.json'] = sha256(contents).digest().hex()
205
    settings.sha1_hashes['index.json']   = sha1(contents).digest().hex()
206

  
207
    with open(settings.index_json_path, 'wb') as file_handle:
208
        file_handle.write(contents)
209

  
210
    return settings
211

  
167 212
@pytest.fixture()
168 213
def tmpdir() -> str:
169 214
    with TemporaryDirectory() as tmpdir:
......
173 218
    """Use sample source package directory as exists in VCS."""
174 219
    return CaseSettings()
175 220

  
176
def prepare_external_index_json(tmpdir: Path) -> dict:
221
def modify_index_good(settings: CaseSettings, obj: dict) -> None:
177 222
    """
178
    Use sample source package directory with an alternative, modified
179
    index.json.
223
    Modify index.json object to make a slightly different but *also correct* one
224
    that can be used to test some different cases.
180 225
    """
181
    settings = CaseSettings()
182

  
183
    from hydrilla_builder.build import strip_json_comments
184

  
185
    with open(settings.srcdir / 'index.json', 'rt') as file_handle:
186
        obj = json.loads(strip_json_comments(file_handle.read()))
187

  
188 226
    # Add comments that should be preserved.
189 227
    for dictionary in (obj, settings.expected_source_description):
190 228
        dictionary['comment'] = 'index_json comment'
......
233 271
            to_process.extend(processed.values())
234 272
            processed['spurious_property'] = 'some value'
235 273

  
236
    # Replace the other index.json with new one
237
    settings.index_json_path = tmpdir / 'replacement.json'
238

  
239
    contents = json.dumps(obj).encode()
240

  
241
    settings.contents['index.json'] = contents
242

  
243
    settings.sha256_hashes['index.json'] = sha256(contents).digest().hex()
244
    settings.sha1_hashes['index.json']   = sha1(contents).digest().hex()
245

  
246
    with open(settings.index_json_path, 'wb') as file_handle:
247
        file_handle.write(contents)
248

  
249
    return settings
250

  
251 274
@pytest.mark.parametrize('prepare_source_example', [
252
    prepare_default, prepare_external_index_json
275
    prepare_default,
276
    lambda tmpdir: prepare_modified(tmpdir, modify_index_good)
253 277
])
254 278
def test_build(tmpdir, prepare_source_example):
255 279
    """Build the sample source package and verify the produced files."""
256
    from hydrilla_builder.build import Build
257

  
258 280
    # First, build the package
259 281
    dstdir = Path(tmpdir) / 'dstdir'
260 282
    tmpdir = Path(tmpdir) / 'example'
......
264 286

  
265 287
    settings = prepare_source_example(tmpdir)
266 288

  
267
    build = Build(settings.srcdir, settings.index_json_path)
268
    build.write_package_files(dstdir)
289
    build.Build(settings.srcdir, settings.index_json_path)\
290
        .write_package_files(dstdir)
269 291

  
270 292
    # Verify directories under destination directory
271 293
    assert {'file', 'resource', 'mapping', 'source'} == \
......
354 376
    with open(source_dir / 'hello.json', 'rt') as file_handle:
355 377
        assert json.load(file_handle) == settings.expected_source_description
356 378

  
357
# TODO: also check error handling
379
def modify_index_missing_file(dummy: CaseSettings, obj: dict) -> None:
380
    """
381
    Modify index.json to expect missing report.spdx file and cause an error.
382
    """
383
    del obj['reuse_generate_spdx_report']
384

  
385
def modify_index_schema_error(dummy: CaseSettings, obj: dict) -> None:
386
    """Modify index.json to be incompliant with the schema."""
387
    del obj['definitions']
388

  
389
def modify_index_bad_comment(dummy: CaseSettings, obj: dict) -> str:
390
    """Modify index.json to have an invalid '/' in it."""
391
    return json.dumps(obj) + '/something\n'
392

  
393
def modify_index_bad_json(dummy: CaseSettings, obj: dict) -> str:
394
    """Modify index.json to not be valid json even after comment stripping."""
395
    return json.dumps(obj) + '???/\n'
396

  
397
def modify_index_missing_license(settings: CaseSettings, obj: dict) -> None:
398
    """Remove a file to make package REUSE-incompliant."""
399
    (settings.srcdir / 'README.txt.license').unlink()
400

  
401
def modify_index_file_outside(dummy: CaseSettings, obj: dict) -> None:
402
    """Make index.json illegally reference a file outside srcdir."""
403
    obj['copyright'].append({'file': '../abc'})
404

  
405
def modify_index_reference_itself(dummy: CaseSettings, obj: dict) -> None:
406
    """Make index.json illegally reference index.json."""
407
    obj['copyright'].append({'file': 'index.json'})
408

  
409
def modify_index_report_excluded(dummy: CaseSettings, obj: dict) -> None:
410
    """
411
    Make index.json require generation of index.json but not include it among
412
    copyright files.
413
    """
414
    obj['copyright'] = [fr for fr in obj['copyright']
415
                        if fr['file'] != 'report.spdx']
416

  
417
@pytest.mark.parametrize('break_index_json', [
418
    (modify_index_missing_file,     FileNotFoundError),
419
    (modify_index_schema_error,     ValidationError),
420
    (modify_index_bad_comment,      json.JSONDecodeError),
421
    (modify_index_bad_json,         json.JSONDecodeError),
422
    (modify_index_missing_license,  build.ReuseError),
423
    (modify_index_file_outside,     build.FileReferenceError),
424
    (modify_index_reference_itself, build.FileReferenceError),
425
    (modify_index_report_excluded,  build.FileReferenceError)
426
])
427
def test_build_error(tmpdir: str, break_index_json: tuple[ModifyCb, type]):
428
    """Build the sample source package and verify the produced files."""
429
    dstdir = Path(tmpdir) / 'dstdir'
430
    tmpdir = Path(tmpdir) / 'example'
431

  
432
    dstdir.mkdir(exist_ok=True)
433
    tmpdir.mkdir(exist_ok=True)
434

  
435
    modify_cb, error_type = break_index_json
436

  
437
    settings = prepare_modified(tmpdir, modify_cb)
438

  
439
    with pytest.raises(error_type):
440
        build.Build(settings.srcdir, settings.index_json_path)\
441
             .write_package_files(dstdir)

Also available in: Unified diff