Skip to content

Commit 57b5282

Browse files
committed
test(policy-inspect): add unit tests for copyleft license source filtering
1 parent 800decf commit 57b5282

File tree

1 file changed

+255
-0
lines changed

1 file changed

+255
-0
lines changed

tests/test_policy_inspect.py

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import unittest
2929
from unittest.mock import Mock, patch
3030

31+
from scanoss.constants import DEFAULT_COPYLEFT_LICENSE_SOURCES
3132
from src.scanoss.inspection.policy_check.dependency_track.project_violation import (
3233
DependencyTrackProjectViolationPolicyCheck,
3334
)
@@ -389,6 +390,260 @@ def test_copyleft_policy_jira_markdown_output(self):
389390
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
390391
self.assertEqual(expected_details_output, results)
391392

393+
## Copyleft License Source Filtering Tests ##
394+
395+
def test_copyleft_policy_default_license_sources(self):
396+
"""
397+
Test default behavior: should use DEFAULT_COPYLEFT_LICENSE_SOURCES
398+
(component_declared and license_file)
399+
"""
400+
script_dir = os.path.dirname(os.path.abspath(__file__))
401+
file_name = 'result.json'
402+
input_file_name = os.path.join(script_dir, 'data', file_name)
403+
copyleft = Copyleft(filepath=input_file_name, format_type='json')
404+
status, policy_output = copyleft.run()
405+
details = json.loads(policy_output.details)
406+
407+
# Should find components with copyleft from component_declared or license_file
408+
# Expected: 5 PURL@version entries (scanner.c x2, engine x2, wfp x1)
409+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
410+
self.assertEqual(len(details['components']), 5)
411+
412+
# Verify all components have licenses from default sources
413+
for component in details['components']:
414+
for license in component['licenses']:
415+
self.assertIn(license['source'], DEFAULT_COPYLEFT_LICENSE_SOURCES)
416+
417+
def test_copyleft_policy_license_sources_none(self):
418+
"""
419+
Test explicit None: should use DEFAULT_COPYLEFT_LICENSE_SOURCES
420+
"""
421+
script_dir = os.path.dirname(os.path.abspath(__file__))
422+
file_name = 'result.json'
423+
input_file_name = os.path.join(script_dir, 'data', file_name)
424+
copyleft = Copyleft(filepath=input_file_name, format_type='json', license_sources=None)
425+
status, policy_output = copyleft.run()
426+
details = json.loads(policy_output.details)
427+
428+
# Should behave same as default
429+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
430+
self.assertEqual(len(details['components']), 5)
431+
432+
# Verify all components have licenses from default sources
433+
for component in details['components']:
434+
for license in component['licenses']:
435+
self.assertIn(license['source'], DEFAULT_COPYLEFT_LICENSE_SOURCES)
436+
437+
438+
def test_copyleft_policy_license_sources_component_declared_only(self):
439+
"""
440+
Test filtering to component_declared source only
441+
Should find GPL-2.0-only from component_declared
442+
"""
443+
script_dir = os.path.dirname(os.path.abspath(__file__))
444+
file_name = 'result.json'
445+
input_file_name = os.path.join(script_dir, 'data', file_name)
446+
copyleft = Copyleft(
447+
filepath=input_file_name,
448+
format_type='json',
449+
license_sources=['component_declared']
450+
)
451+
status, policy_output = copyleft.run()
452+
details = json.loads(policy_output.details)
453+
454+
# Should find 5 PURL@version entries from component_declared
455+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
456+
self.assertEqual(len(details['components']), 5)
457+
458+
# All licenses should be from component_declared
459+
for component in details['components']:
460+
for license in component['licenses']:
461+
self.assertEqual(license['source'], 'component_declared')
462+
463+
def test_copyleft_policy_license_sources_license_file_only(self):
464+
"""
465+
Test filtering to license_file source only
466+
Should find GPL-2.0-only from license_file (engine and wfp)
467+
"""
468+
script_dir = os.path.dirname(os.path.abspath(__file__))
469+
file_name = 'result.json'
470+
input_file_name = os.path.join(script_dir, 'data', file_name)
471+
copyleft = Copyleft(
472+
filepath=input_file_name,
473+
format_type='json',
474+
license_sources=['license_file']
475+
)
476+
status, policy_output = copyleft.run()
477+
details = json.loads(policy_output.details)
478+
479+
# Should find engine and wfp (2 components with license_file)
480+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
481+
self.assertEqual(len(details['components']), 2)
482+
483+
# Verify components are engine and wfp
484+
purls = [comp['purl'] for comp in details['components']]
485+
self.assertIn('pkg:github/scanoss/engine', purls)
486+
self.assertIn('pkg:github/scanoss/wfp', purls)
487+
488+
# All licenses should be from license_file
489+
for component in details['components']:
490+
for license in component['licenses']:
491+
self.assertEqual(license['source'], 'license_file')
492+
493+
def test_copyleft_policy_license_sources_file_header_only(self):
494+
"""
495+
Test filtering to file_header source only
496+
file_header only has BSD-2-Clause and Zlib (not copyleft)
497+
Should find no copyleft licenses
498+
"""
499+
script_dir = os.path.dirname(os.path.abspath(__file__))
500+
file_name = 'result.json'
501+
input_file_name = os.path.join(script_dir, 'data', file_name)
502+
copyleft = Copyleft(
503+
filepath=input_file_name,
504+
format_type='json',
505+
license_sources=['file_header']
506+
)
507+
status, policy_output = copyleft.run()
508+
details = json.loads(policy_output.details)
509+
510+
# Should find no copyleft (file_header only has BSD and Zlib)
511+
self.assertEqual(status, PolicyStatus.POLICY_SUCCESS.value)
512+
self.assertEqual(details, {})
513+
514+
def test_copyleft_policy_license_sources_multiple_sources(self):
515+
"""
516+
Test using multiple license sources
517+
Should find copyleft from component_declared and scancode
518+
"""
519+
script_dir = os.path.dirname(os.path.abspath(__file__))
520+
file_name = 'result.json'
521+
input_file_name = os.path.join(script_dir, 'data', file_name)
522+
copyleft = Copyleft(
523+
filepath=input_file_name,
524+
format_type='json',
525+
license_sources=['component_declared', 'scancode']
526+
)
527+
status, policy_output = copyleft.run()
528+
details = json.loads(policy_output.details)
529+
530+
# Should find components from both sources
531+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
532+
self.assertGreaterEqual(len(details['components']), 3)
533+
534+
# Verify licenses are from specified sources
535+
for component in details['components']:
536+
for license in component['licenses']:
537+
self.assertIn(license['source'], ['component_declared', 'scancode'])
538+
539+
def test_copyleft_policy_license_sources_all_valid_sources(self):
540+
"""
541+
Test using all valid license sources
542+
"""
543+
script_dir = os.path.dirname(os.path.abspath(__file__))
544+
file_name = 'result.json'
545+
input_file_name = os.path.join(script_dir, 'data', file_name)
546+
from scanoss.constants import VALID_LICENSE_SOURCES
547+
copyleft = Copyleft(
548+
filepath=input_file_name,
549+
format_type='json',
550+
license_sources=VALID_LICENSE_SOURCES
551+
)
552+
status, policy_output = copyleft.run()
553+
details = json.loads(policy_output.details)
554+
555+
# Should find all copyleft licenses from any source
556+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
557+
self.assertGreaterEqual(len(details['components']), 3)
558+
559+
def test_copyleft_policy_license_sources_with_markdown_output(self):
560+
"""
561+
Test license source filtering works with markdown output
562+
"""
563+
script_dir = os.path.dirname(os.path.abspath(__file__))
564+
file_name = 'result.json'
565+
input_file_name = os.path.join(script_dir, 'data', file_name)
566+
copyleft = Copyleft(
567+
filepath=input_file_name,
568+
format_type='md',
569+
license_sources=['license_file']
570+
)
571+
status, policy_output = copyleft.run()
572+
573+
# Should generate markdown table
574+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
575+
self.assertIn('### Copyleft Licenses', policy_output.details)
576+
self.assertIn('Component', policy_output.details)
577+
self.assertIn('License', policy_output.details)
578+
self.assertIn('2 component(s) with copyleft licenses were found', policy_output.summary)
579+
580+
def test_copyleft_policy_license_sources_with_include_filter(self):
581+
"""
582+
Test license_sources works with include filter
583+
Filter to scancode source and include only GPL-2.0-or-later
584+
"""
585+
script_dir = os.path.dirname(os.path.abspath(__file__))
586+
file_name = 'result.json'
587+
input_file_name = os.path.join(script_dir, 'data', file_name)
588+
copyleft = Copyleft(
589+
filepath=input_file_name,
590+
format_type='json',
591+
license_sources=['scancode'],
592+
include='GPL-2.0-or-later'
593+
)
594+
status, policy_output = copyleft.run()
595+
details = json.loads(policy_output.details)
596+
597+
# Should find only GPL-2.0-or-later from scancode
598+
self.assertEqual(status, PolicyStatus.POLICY_FAIL.value)
599+
if details: # May be empty if no matches
600+
for component in details.get('components', []):
601+
for license in component['licenses']:
602+
self.assertEqual(license['spdxid'], 'GPL-2.0-or-later')
603+
self.assertEqual(license['source'], 'scancode')
604+
605+
def test_copyleft_policy_license_sources_with_exclude_filter(self):
606+
"""
607+
Test license_sources works with exclude filter
608+
Use component_declared but exclude GPL-2.0-only
609+
"""
610+
script_dir = os.path.dirname(os.path.abspath(__file__))
611+
file_name = 'result.json'
612+
input_file_name = os.path.join(script_dir, 'data', file_name)
613+
copyleft = Copyleft(
614+
filepath=input_file_name,
615+
format_type='json',
616+
license_sources=['component_declared'],
617+
exclude='GPL-2.0-only'
618+
)
619+
status, policy_output = copyleft.run()
620+
details = json.loads(policy_output.details)
621+
622+
# Should exclude GPL-2.0-only, leaving nothing (all component_declared are GPL-2.0-only)
623+
self.assertEqual(status, PolicyStatus.POLICY_SUCCESS.value)
624+
self.assertEqual(details, {})
625+
626+
def test_copyleft_policy_license_sources_no_copyleft_file(self):
627+
"""
628+
Test license_sources with result-no-copyleft.json
629+
Should return success even with license_sources specified
630+
"""
631+
script_dir = os.path.dirname(os.path.abspath(__file__))
632+
file_name = 'result-no-copyleft.json'
633+
input_file_name = os.path.join(script_dir, 'data', file_name)
634+
copyleft = Copyleft(
635+
filepath=input_file_name,
636+
format_type='json',
637+
license_sources=['component_declared']
638+
)
639+
status, policy_output = copyleft.run()
640+
details = json.loads(policy_output.details)
641+
642+
# Should find no copyleft
643+
self.assertEqual(status, PolicyStatus.POLICY_SUCCESS.value)
644+
self.assertEqual(details, {})
645+
self.assertIn('0 component(s) with copyleft licenses were found', policy_output.summary)
646+
392647
def test_inspect_license_summary(self):
393648
script_dir = os.path.dirname(os.path.abspath(__file__))
394649
file_name = 'result.json'

0 commit comments

Comments
 (0)