10 |
10 |
import pytest
|
11 |
11 |
import json
|
12 |
12 |
import shutil
|
|
13 |
import functools as ft
|
13 |
14 |
|
14 |
15 |
from tempfile import TemporaryDirectory
|
15 |
16 |
from pathlib import Path, PurePosixPath
|
... | ... | |
255 |
256 |
|
256 |
257 |
yield sample_source
|
257 |
258 |
|
|
259 |
def collect(list):
|
|
260 |
"""Decorate function by appending it to the specified list."""
|
|
261 |
def decorator(function):
|
|
262 |
"""The actual decorator that will be applied."""
|
|
263 |
list.append(function)
|
|
264 |
return function
|
|
265 |
|
|
266 |
return decorator
|
|
267 |
|
258 |
268 |
variant_makers = []
|
259 |
|
def variant_maker(function):
|
260 |
|
"""Decorate function by placing it in variant_makers array."""
|
261 |
|
variant_makers.append(function)
|
262 |
|
return function
|
263 |
269 |
|
264 |
|
@variant_maker
|
|
270 |
@collect(variant_makers)
|
265 |
271 |
def sample_source_change_index_json(monkeypatch, sample_source):
|
266 |
272 |
"""
|
267 |
273 |
Return a non-standard path for index.json. Ensure parent directories exist.
|
... | ... | |
272 |
278 |
path.parent.mkdir()
|
273 |
279 |
return path
|
274 |
280 |
|
275 |
|
@variant_maker
|
|
281 |
@collect(variant_makers)
|
276 |
282 |
def sample_source_add_comments(monkeypatch, sample_source):
|
277 |
283 |
"""Add index.json comments that should be preserved."""
|
278 |
284 |
for dictionary in index_obj, *index_obj['definitions'], *expected:
|
279 |
285 |
monkeypatch.setitem(dictionary, 'comment', 'index.json comment')
|
280 |
286 |
|
281 |
|
@variant_maker
|
|
287 |
@collect(variant_makers)
|
282 |
288 |
def sample_source_remove_spdx(monkeypatch, sample_source):
|
283 |
289 |
"""Remove spdx report generation."""
|
284 |
290 |
monkeypatch.delitem(index_obj, 'reuse_generate_spdx_report')
|
... | ... | |
297 |
303 |
# raise an error if called.
|
298 |
304 |
(sample_source / 'mock_reuse_missing').touch()
|
299 |
305 |
|
300 |
|
@variant_maker
|
|
306 |
@collect(variant_makers)
|
301 |
307 |
def sample_source_remove_additional_files(monkeypatch, sample_source):
|
302 |
308 |
"""Use default value ([]) for 'additionall_files' property."""
|
303 |
309 |
monkeypatch.delitem(index_obj, 'additional_files')
|
... | ... | |
305 |
311 |
for name in 'README.txt', 'README.txt.license', '.reuse/dep5':
|
306 |
312 |
monkeypatch.delitem(src_files, name)
|
307 |
313 |
|
308 |
|
@variant_maker
|
|
314 |
@collect(variant_makers)
|
309 |
315 |
def sample_source_remove_script(monkeypatch, sample_source):
|
310 |
316 |
"""Use default value ([]) for 'scripts' property in one of the resources."""
|
311 |
317 |
monkeypatch.delitem(index_obj['definitions'][2], 'scripts')
|
... | ... | |
315 |
321 |
for files in dist_files, src_files:
|
316 |
322 |
monkeypatch.delitem(files, 'message.js')
|
317 |
323 |
|
318 |
|
@variant_maker
|
|
324 |
@collect(variant_makers)
|
319 |
325 |
def sample_source_remove_payloads(monkeypatch, sample_source):
|
320 |
326 |
"""Use default value ({}) for 'payloads' property in mapping."""
|
321 |
327 |
monkeypatch.delitem(index_obj['definitions'][0], 'payloads')
|
322 |
328 |
|
323 |
329 |
monkeypatch.setitem(expected_mapping, 'payloads', {})
|
324 |
330 |
|
325 |
|
@variant_maker
|
|
331 |
@collect(variant_makers)
|
326 |
332 |
def sample_source_remove_uuids(monkeypatch, sample_source):
|
327 |
333 |
"""Don't use UUIDs (they are optional)."""
|
328 |
334 |
for definition in index_obj['definitions']:
|
... | ... | |
332 |
338 |
if 'uuid' in description:
|
333 |
339 |
monkeypatch.delitem(description, 'uuid')
|
334 |
340 |
|
335 |
|
@variant_maker
|
|
341 |
@collect(variant_makers)
|
336 |
342 |
def sample_source_add_extra_props(monkeypatch, sample_source):
|
337 |
343 |
"""Add some unrecognized properties that should be stripped."""
|
338 |
344 |
to_process = [index_obj]
|
... | ... | |
346 |
352 |
if k != 'payloads')
|
347 |
353 |
monkeypatch.setitem(processed, 'spurious_property', 'some_value')
|
348 |
354 |
|
349 |
|
@variant_maker
|
|
355 |
@collect(variant_makers)
|
350 |
356 |
def sample_source_make_version_2(monkeypatch, sample_source,
|
351 |
357 |
expected_documents_to_modify=[]):
|
352 |
|
"""Increase sources' schema version from to 2."""
|
|
358 |
"""Increase sources' schema version from 1 to 2."""
|
353 |
359 |
for obj in index_obj, *expected_documents_to_modify:
|
354 |
360 |
monkeypatch.setitem(obj, '$schema', obj['$schema'].replace('1', '2'))
|
355 |
361 |
|
356 |
|
@variant_maker
|
357 |
|
def sample_source_cors_bypass_ignored(monkeypatch, sample_source, value=True):
|
|
362 |
permission_variant_makers = []
|
|
363 |
|
|
364 |
@collect(permission_variant_makers)
|
|
365 |
def sample_source_bool_perm_ignored(permission, monkeypatch, sample_source,
|
|
366 |
value=True):
|
358 |
367 |
"""
|
359 |
|
Specify CORS bypass permissions in sources, but keep sources' schema version
|
|
368 |
Specify a boolean permissions in sources, but keep sources' schema version
|
360 |
369 |
at 1.
|
361 |
370 |
"""
|
362 |
371 |
for definition in index_obj['definitions']:
|
363 |
|
monkeypatch.setitem(definition, 'permissions', {'cors_bypass': value})
|
|
372 |
monkeypatch.setitem(definition, 'permissions', {permission: value})
|
364 |
373 |
|
365 |
|
@variant_maker
|
366 |
|
def sample_source_cors_bypass(monkeypatch, sample_source):
|
367 |
|
"""Specify CORS bypass permissions in sources."""
|
368 |
|
sample_source_cors_bypass_ignored(monkeypatch, sample_source, value=True)
|
|
374 |
@collect(permission_variant_makers)
|
|
375 |
def sample_source_bool_perm(permission, monkeypatch, sample_source):
|
|
376 |
"""Specify a boolean permission in sources."""
|
|
377 |
sample_source_bool_perm_ignored(permission, monkeypatch, sample_source)
|
369 |
378 |
sample_source_make_version_2(monkeypatch, sample_source, expected_items)
|
370 |
379 |
|
371 |
380 |
for obj in expected_items:
|
372 |
|
monkeypatch.setitem(obj, 'permissions', {'cors_bypass': True})
|
|
381 |
monkeypatch.setitem(obj, 'permissions', {permission: True})
|
373 |
382 |
|
374 |
|
@variant_maker
|
375 |
|
def sample_source_cors_bypass_defaults(monkeypatch, sample_source):
|
|
383 |
@collect(permission_variant_makers)
|
|
384 |
def sample_source_bool_perm_defaults(permission, monkeypatch, sample_source):
|
376 |
385 |
"""
|
377 |
|
Specify CORS bypass permissions in sources but use the default value
|
378 |
|
("False").
|
|
386 |
Specify a boolean permission in sources but use the default value ("False").
|
379 |
387 |
"""
|
380 |
|
sample_source_cors_bypass_ignored(monkeypatch, sample_source, value=False)
|
|
388 |
sample_source_bool_perm_ignored(permission, monkeypatch, sample_source,
|
|
389 |
value=False)
|
381 |
390 |
sample_source_make_version_2(monkeypatch, sample_source)
|
382 |
391 |
|
383 |
|
@variant_maker
|
|
392 |
for permission in 'cors_bypass', 'eval':
|
|
393 |
for variant_maker in permission_variant_makers:
|
|
394 |
variant_makers.append(ft.partial(variant_maker, permission))
|
|
395 |
|
|
396 |
@collect(variant_makers)
|
384 |
397 |
def sample_source_req_mappings_ignored(monkeypatch, sample_source,
|
385 |
398 |
value=[{'identifier': 'mapping-dep'}]):
|
386 |
399 |
"""
|
... | ... | |
389 |
402 |
for definition in index_obj['definitions']:
|
390 |
403 |
monkeypatch.setitem(definition, 'required_mappings', value);
|
391 |
404 |
|
392 |
|
@variant_maker
|
|
405 |
@collect(variant_makers)
|
393 |
406 |
def sample_source_req_mappings(monkeypatch, sample_source):
|
394 |
407 |
"""Specify dependencies on mappings."""
|
395 |
408 |
sample_source_req_mappings_ignored(monkeypatch, sample_source)
|
... | ... | |
399 |
412 |
monkeypatch.setitem(obj, 'required_mappings',
|
400 |
413 |
[{'identifier': 'mapping-dep'}])
|
401 |
414 |
|
402 |
|
@variant_maker
|
|
415 |
@collect(variant_makers)
|
403 |
416 |
def sample_source_req_mappings_defaults(monkeypatch, sample_source):
|
404 |
417 |
"""Specify dependencies of a mapping, but use the default value ("[]")."""
|
405 |
418 |
sample_source_req_mappings_ignored(monkeypatch, sample_source, value=[])
|
406 |
419 |
sample_source_make_version_2(monkeypatch, sample_source)
|
407 |
420 |
|
408 |
|
@variant_maker
|
|
421 |
@collect(variant_makers)
|
409 |
422 |
def sample_source_combined_def(monkeypatch, sample_source):
|
410 |
423 |
"""Define mapping and resource together."""
|
411 |
424 |
sample_source_make_version_2(monkeypatch, sample_source)
|
... | ... | |
432 |
445 |
monkeypatch.setitem(expected_source_description['definitions'][0],
|
433 |
446 |
'version', new_mapping_ver)
|
434 |
447 |
|
435 |
|
@variant_maker
|
|
448 |
@collect(variant_makers)
|
436 |
449 |
def sample_source_minmax_haketilo_ver_ignored(monkeypatch, sample_source,
|
437 |
450 |
min_ver=[1, 2], max_ver=[1, 2]):
|
438 |
451 |
"""
|
... | ... | |
443 |
456 |
monkeypatch.setitem(mapping_def, 'min_haketilo_version', min_ver)
|
444 |
457 |
monkeypatch.setitem(mapping_def, 'max_haketilo_version', max_ver)
|
445 |
458 |
|
446 |
|
@variant_maker
|
|
459 |
@collect(variant_makers)
|
447 |
460 |
def sample_source_minmax_haketilo_ver(monkeypatch, sample_source):
|
448 |
461 |
"""Specify version constraints on Haketilo."""
|
449 |
462 |
sample_source_minmax_haketilo_ver_ignored(monkeypatch, sample_source)
|
... | ... | |
452 |
465 |
monkeypatch.setitem(expected_mapping, 'min_haketilo_version', [1, 2])
|
453 |
466 |
monkeypatch.setitem(expected_mapping, 'max_haketilo_version', [1, 2])
|
454 |
467 |
|
455 |
|
@variant_maker
|
|
468 |
@collect(variant_makers)
|
456 |
469 |
def sample_source_minmax_haketilo_ver_default(monkeypatch, sample_source):
|
457 |
470 |
"""Specify version constraints on Haketilo, but use default values."""
|
458 |
471 |
sample_source_minmax_haketilo_ver_ignored(monkeypatch, sample_source,
|
... | ... | |
466 |
479 |
'othersystem/other-something.tar.gz'
|
467 |
480 |
]
|
468 |
481 |
|
469 |
|
@variant_maker
|
|
482 |
@collect(variant_makers)
|
470 |
483 |
def sample_source_add_piggyback_ignored(monkeypatch, sample_source,
|
471 |
484 |
extra_build_args={}):
|
472 |
485 |
"""
|
... | ... | |
484 |
497 |
'dependencies': False
|
485 |
498 |
})
|
486 |
499 |
|
487 |
|
@variant_maker
|
|
500 |
@collect(variant_makers)
|
488 |
501 |
def sample_source_add_piggyback(monkeypatch, sample_source,
|
489 |
502 |
extra_build_args={}):
|
490 |
503 |
"""Add piggybacked foreign system packages."""
|
... | ... | |
528 |
541 |
archive_path.parent.mkdir(parents=True, exist_ok=True)
|
529 |
542 |
archive_path.write_text(f'dummy {archive_path.name}')
|
530 |
543 |
|
531 |
|
@variant_maker
|
|
544 |
@collect(variant_makers)
|
532 |
545 |
def sample_source_add_piggyback_pass_archives(monkeypatch, sample_source):
|
533 |
546 |
"""
|
534 |
547 |
Add piggybacked foreign system packages, use pre-downloaded foreign package
|
... | ... | |
542 |
555 |
sample_source_add_piggyback(monkeypatch, sample_source,
|
543 |
556 |
{'piggyback_files': foreign_packages_dir})
|
544 |
557 |
|
545 |
|
@variant_maker
|
|
558 |
@collect(variant_makers)
|
546 |
559 |
def sample_source_add_piggyback_find_archives(monkeypatch, sample_source):
|
547 |
560 |
"""
|
548 |
561 |
Add piggybacked foreign system packages, use pre-downloaded foreign package
|
... | ... | |
555 |
568 |
|
556 |
569 |
sample_source_add_piggyback(monkeypatch, sample_source)
|
557 |
570 |
|
558 |
|
@variant_maker
|
|
571 |
@collect(variant_makers)
|
559 |
572 |
def sample_source_add_piggyback_no_download(monkeypatch, sample_source,
|
560 |
573 |
pass_directory_to_build=False):
|
561 |
574 |
"""
|
... | ... | |
678 |
691 |
try_validate('api_source_description', expected_source_description)
|
679 |
692 |
|
680 |
693 |
error_makers = []
|
681 |
|
def error_maker(function):
|
682 |
|
"""Decorate function by placing it in error_makers array."""
|
683 |
|
error_makers.append(function)
|
684 |
694 |
|
685 |
|
@error_maker
|
|
695 |
@collect(error_makers)
|
686 |
696 |
def sample_source_error_missing_file(monkeypatch, sample_source):
|
687 |
697 |
"""
|
688 |
698 |
Modify index.json to expect missing report.spdx file and cause an error.
|
... | ... | |
690 |
700 |
monkeypatch.delitem(index_obj, 'reuse_generate_spdx_report')
|
691 |
701 |
return FileReferenceError, '^referenced_file_report.spdx_missing$'
|
692 |
702 |
|
693 |
|
@error_maker
|
|
703 |
@collect(error_makers)
|
694 |
704 |
def sample_source_error_index_schema(monkeypatch, sample_source):
|
695 |
705 |
"""Modify index.json to be incompliant with the schema."""
|
696 |
706 |
monkeypatch.delitem(index_obj, 'definitions')
|
697 |
707 |
return ValidationError,
|
698 |
708 |
|
699 |
|
@error_maker
|
|
709 |
@collect(error_makers)
|
700 |
710 |
def sample_source_error_bad_comment(monkeypatch, sample_source):
|
701 |
711 |
"""Modify index.json to have an invalid '/' in it."""
|
702 |
712 |
return json.JSONDecodeError, '^bad_comment: .*', \
|
703 |
713 |
json.dumps(index_obj) + '/something\n'
|
704 |
714 |
|
705 |
|
@error_maker
|
|
715 |
@collect(error_makers)
|
706 |
716 |
def sample_source_error_bad_json(monkeypatch, sample_source):
|
707 |
717 |
"""Modify index.json to not be valid json even after comment stripping."""
|
708 |
718 |
return json.JSONDecodeError, '', json.dumps(index_obj) + '???\n'
|
709 |
719 |
|
710 |
|
@error_maker
|
|
720 |
@collect(error_makers)
|
711 |
721 |
def sample_source_error_missing_reuse(monkeypatch, sample_source):
|
712 |
722 |
"""Cause mocked reuse process invocation to fail with FileNotFoundError."""
|
713 |
723 |
(sample_source / 'mock_reuse_missing').touch()
|
714 |
724 |
return build.ReuseError, '^couldnt_execute_reuse_is_it_installed$'
|
715 |
725 |
|
716 |
|
@error_maker
|
|
726 |
@collect(error_makers)
|
717 |
727 |
def sample_source_error_missing_license(monkeypatch, sample_source):
|
718 |
728 |
"""Remove a file to make package REUSE-incompliant."""
|
719 |
729 |
(sample_source / 'README.txt.license').unlink()
|
... | ... | |
733 |
743 |
|
734 |
744 |
return build.ReuseError, error_regex
|
735 |
745 |
|
736 |
|
@error_maker
|
|
746 |
@collect(error_makers)
|
737 |
747 |
def sample_source_error_file_outside(monkeypatch, sample_source):
|
738 |
748 |
"""Make index.json illegally reference a file outside srcdir."""
|
739 |
749 |
new_list = [*index_obj['copyright'], {'file': '../abc'}]
|
740 |
750 |
monkeypatch.setitem(index_obj, 'copyright', new_list)
|
741 |
751 |
return FileReferenceError, '^path_contains_double_dot_\\.\\./abc$'
|
742 |
752 |
|
743 |
|
@error_maker
|
|
753 |
@collect(error_makers)
|
744 |
754 |
def sample_source_error_reference_itself(monkeypatch, sample_source):
|
745 |
755 |
"""Make index.json illegally reference index.json."""
|
746 |
756 |
new_list = [*index_obj['copyright'], {'file': 'index.json'}]
|
747 |
757 |
monkeypatch.setitem(index_obj, 'copyright', new_list)
|
748 |
758 |
return FileReferenceError, '^loading_reserved_index_json$'
|
749 |
759 |
|
750 |
|
@error_maker
|
|
760 |
@collect(error_makers)
|
751 |
761 |
def sample_source_error_report_excluded(monkeypatch, sample_source):
|
752 |
762 |
"""
|
753 |
763 |
Make index.json require generation of report.spdx but don't include it among
|
... | ... | |
758 |
768 |
monkeypatch.setitem(index_obj, 'copyright', new_list)
|
759 |
769 |
return FileReferenceError, '^report_spdx_not_in_copyright_list$'
|
760 |
770 |
|
761 |
|
@error_maker
|
|
771 |
@collect(error_makers)
|
762 |
772 |
def sample_source_error_combined_unsupported(monkeypatch, sample_source):
|
763 |
773 |
"""
|
764 |
774 |
Define mapping and resource together but leave source schema version at 1.x
|
add "eval" permission