diff --git a/src/deltacode/__init__.py b/src/deltacode/__init__.py index 0a68fcd9..6b6f46f0 100644 --- a/src/deltacode/__init__.py +++ b/src/deltacode/__init__.py @@ -84,7 +84,11 @@ def determine_delta(self): deltas['unmodified'].append(Delta(new_file, f, 'unmodified')) continue else: - deltas['modified'].append(Delta(new_file, f, 'modified')) + delta = Delta(new_file, f, 'modified') + # Change the Delta object's 'category' attribute to + # 'license change' if a substantial license change has been detected. + delta.license_diff() + deltas['modified'].append(delta) # now time to find the added. for path, old_files in old_index.items(): @@ -124,11 +128,11 @@ def get_stats(self): def to_dict(self): """ - Given an OrderedDict of Delta objects, return an OrderedDict with a - 'deltacode_version' field, a 'deltacode_stats' field, a 'deltas_count' - field, and a 'deltas' field containing a list of our Delta objects. + Given an OrderedDict of Delta objects, return an OrderedDict of Delta + objects grouping the objects under the keys 'added', 'removed', + 'modified' or 'unmodified'. """ - if self.deltas == None: + if self.deltas is None: return return OrderedDict([ @@ -151,8 +155,40 @@ def __init__(self, new_file=None, old_file=None, delta_type=None): self.old_file = old_file self.category = delta_type + def license_diff(self): + """ + Compare the license details for a pair of 'new' and 'old' File objects + in a Delta object and change the Delta object's 'category' attribute to + 'license change' if those details differ and the cutoff score test is + satisfied. + """ + if self.new_file is None or self.old_file is None: + return + + cutoff_score = 50 + + if self.new_file.licenses: + new_keys = [l.key for l in self.new_file.licenses if l.score >= cutoff_score] + else: + new_keys = [] + + if self.old_file.licenses: + old_keys = [l.key for l in self.old_file.licenses if l.score >= cutoff_score] + else: + old_keys = [] + + new_keys = list(set(new_keys)) + old_keys = list(set(old_keys)) + + if new_keys != old_keys: + self.category = 'license change' + def to_dict(self): - if self.new_file == None and self.old_file == None: + """ + Check the 'category' attribute of the Delta object and return an + OrderedDict comprising the 'category' and 'path' of the object. + """ + if self.new_file is None and self.old_file is None: return if self.category == 'added': @@ -168,10 +204,15 @@ def to_dict(self): elif self.category == 'modified': return OrderedDict([ ('category', 'modified'), - ('path', self.old_file.path) + ('path', self.new_file.path) + ]) + elif self.category == 'license change': + return OrderedDict([ + ('category', 'license change'), + ('path', self.new_file.path) ]) else: return OrderedDict([ ('category', 'unmodified'), - ('path', self.old_file.path) + ('path', self.new_file.path) ]) diff --git a/tests/data/cli/modified_new_license_added.csv b/tests/data/cli/modified_new_license_added.csv new file mode 100644 index 00000000..884024db --- /dev/null +++ b/tests/data/cli/modified_new_license_added.csv @@ -0,0 +1,4 @@ +Type of delta,Path +modified,some/path/c/c1.py +license change,some/path/a/a1.py +license change,some/path/b/b1.py diff --git a/tests/data/cli/modified_new_license_added_low_score.csv b/tests/data/cli/modified_new_license_added_low_score.csv new file mode 100644 index 00000000..fe375433 --- /dev/null +++ b/tests/data/cli/modified_new_license_added_low_score.csv @@ -0,0 +1,3 @@ +Type of delta,Path +modified,some/path/a/a1.py +modified,some/path/b/b1.py diff --git a/tests/data/cli/scan_modified_new_license_added.json b/tests/data/cli/scan_modified_new_license_added.json new file mode 100644 index 00000000..9979c9c8 --- /dev/null +++ b/tests/data/cli/scan_modified_new_license_added.json @@ -0,0 +1,92 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 3, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 300, + "sha1": "000647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + }, + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 300, + "sha1": "111647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "gpl-2.0", + "score": 60.0, + "short_name": "GPL 2.0", + "category": "Copyleft" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + }, + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/c/c1.py", + "type": "file", + "name": "c1.py", + "size": 300, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/cli/scan_modified_new_license_added_low_score.json b/tests/data/cli/scan_modified_new_license_added_low_score.json new file mode 100644 index 00000000..5fc801a4 --- /dev/null +++ b/tests/data/cli/scan_modified_new_license_added_low_score.json @@ -0,0 +1,59 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 350, + "sha1": "222647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + }, + { + "key": "bsd-simplified", + "score": 40.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 290, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + }, + { + "key": "bsd-simplified", + "score": 30.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/cli/scan_modified_old_license_added.json b/tests/data/cli/scan_modified_old_license_added.json new file mode 100644 index 00000000..a50676a0 --- /dev/null +++ b/tests/data/cli/scan_modified_old_license_added.json @@ -0,0 +1,80 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 3, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 200, + "sha1": "84b647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "public-domain", + "score": 10.0, + "short_name": "Public Domain", + "category": "Public Domain" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b2.py", + "size": 200, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mpl-2.0", + "score": 90.0, + "short_name": "MPL 2.0", + "category": "Copyleft Limited" + }, + { + "key": "public-domain", + "score": 10.0, + "short_name": "Public Domain", + "category": "Public Domain" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/c/c1.py", + "type": "file", + "name": "c1.py", + "size": 300, + "sha1": "222647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/cli/scan_modified_old_license_added_low_score.json b/tests/data/cli/scan_modified_old_license_added_low_score.json new file mode 100644 index 00000000..0c0a790b --- /dev/null +++ b/tests/data/cli/scan_modified_old_license_added_low_score.json @@ -0,0 +1,47 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 300, + "sha1": "000647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 300, + "sha1": "111647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/deltacode/scan_modified_new_license_added.json b/tests/data/deltacode/scan_modified_new_license_added.json new file mode 100644 index 00000000..9979c9c8 --- /dev/null +++ b/tests/data/deltacode/scan_modified_new_license_added.json @@ -0,0 +1,92 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 3, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 300, + "sha1": "000647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + }, + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 300, + "sha1": "111647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "gpl-2.0", + "score": 60.0, + "short_name": "GPL 2.0", + "category": "Copyleft" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + }, + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/c/c1.py", + "type": "file", + "name": "c1.py", + "size": 300, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/deltacode/scan_modified_new_license_added_low_score.json b/tests/data/deltacode/scan_modified_new_license_added_low_score.json new file mode 100644 index 00000000..5fc801a4 --- /dev/null +++ b/tests/data/deltacode/scan_modified_new_license_added_low_score.json @@ -0,0 +1,59 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 350, + "sha1": "222647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + }, + { + "key": "bsd-simplified", + "score": 40.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 290, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + }, + { + "key": "bsd-simplified", + "score": 30.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/deltacode/scan_modified_new_no_license_changes.json b/tests/data/deltacode/scan_modified_new_no_license_changes.json new file mode 100644 index 00000000..b403522c --- /dev/null +++ b/tests/data/deltacode/scan_modified_new_no_license_changes.json @@ -0,0 +1,47 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 400, + "sha1": "222647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 350, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/deltacode/scan_modified_new_no_license_key.json b/tests/data/deltacode/scan_modified_new_no_license_key.json new file mode 100644 index 00000000..7cfb6473 --- /dev/null +++ b/tests/data/deltacode/scan_modified_new_no_license_key.json @@ -0,0 +1,24 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 250, + "sha1": "000647771481d39dd3a53f6dc210c26abac37748" + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 310, + "sha1": "111647771481d39dd3a53f6dc210c26abac37748" + } + ] + } diff --git a/tests/data/deltacode/scan_modified_old_license_added.json b/tests/data/deltacode/scan_modified_old_license_added.json new file mode 100644 index 00000000..a50676a0 --- /dev/null +++ b/tests/data/deltacode/scan_modified_old_license_added.json @@ -0,0 +1,80 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 3, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 200, + "sha1": "84b647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "public-domain", + "score": 10.0, + "short_name": "Public Domain", + "category": "Public Domain" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b2.py", + "size": 200, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mpl-2.0", + "score": 90.0, + "short_name": "MPL 2.0", + "category": "Copyleft Limited" + }, + { + "key": "public-domain", + "score": 10.0, + "short_name": "Public Domain", + "category": "Public Domain" + }, + { + "key": "bsd-simplified", + "score": 100.0, + "short_name": "BSD-Simplified", + "category": "Permissive" + } + ] + }, + { + "path": "some/path/c/c1.py", + "type": "file", + "name": "c1.py", + "size": 300, + "sha1": "222647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/deltacode/scan_modified_old_license_added_low_score.json b/tests/data/deltacode/scan_modified_old_license_added_low_score.json new file mode 100644 index 00000000..0c0a790b --- /dev/null +++ b/tests/data/deltacode/scan_modified_old_license_added_low_score.json @@ -0,0 +1,47 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 300, + "sha1": "000647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 300, + "sha1": "111647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/deltacode/scan_modified_old_no_license_changes.json b/tests/data/deltacode/scan_modified_old_no_license_changes.json new file mode 100644 index 00000000..0c0a790b --- /dev/null +++ b/tests/data/deltacode/scan_modified_old_no_license_changes.json @@ -0,0 +1,47 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--license": true, + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 300, + "sha1": "000647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "apache-2.0", + "score": 80.0, + "short_name": "Apache 2.0", + "category": "Permissive" + }, + { + "key": "agpl-2.0", + "score": 70.0, + "short_name": "AGPL 2.0", + "category": "Copyleft" + } + ] + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 300, + "sha1": "111647771481d39dd3a53f6dc210c26abac37748", + "licenses": [ + { + "key": "mit", + "score": 100.0, + "short_name": "MIT License", + "category": "Permissive" + } + ] + } + ] + } diff --git a/tests/data/deltacode/scan_modified_old_no_license_key.json b/tests/data/deltacode/scan_modified_old_no_license_key.json new file mode 100644 index 00000000..441c86fc --- /dev/null +++ b/tests/data/deltacode/scan_modified_old_no_license_key.json @@ -0,0 +1,24 @@ +{ + "scancode_notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", + "scancode_version": "2.1.0", + "scancode_options": { + "--info": true + }, + "files_count": 2, + "files": [ + { + "path": "some/path/a/a1.py", + "type": "file", + "name": "a1.py", + "size": 350, + "sha1": "222647771481d39dd3a53f6dc210c26abac37748" + }, + { + "path": "some/path/b/b1.py", + "type": "file", + "name": "b1.py", + "size": 290, + "sha1": "333647771481d39dd3a53f6dc210c26abac37748" + } + ] + } diff --git a/tests/test_cli.py b/tests/test_cli.py index f3b57313..ac39a6c9 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -92,3 +92,23 @@ def test_generate_csv_renamed(self): cli.generate_csv(delta, result_file) expected_file = self.get_test_loc('cli/renamed1.csv') check_csvs(result_file, expected_file) + + def test_generate_csv_modified_new_license_added(self): + new_scan = self.get_test_loc('cli/scan_modified_new_license_added.json') + old_scan = self.get_test_loc('cli/scan_modified_old_license_added.json') + + delta = DeltaCode(new_scan, old_scan) + result_file = self.get_temp_file('.csv') + cli.generate_csv(delta, result_file) + expected_file = self.get_test_loc('cli/modified_new_license_added.csv') + check_csvs(result_file, expected_file) + + def test_generate_csv_modified_new_license_added_low_score(self): + new_scan = self.get_test_loc('cli/scan_modified_new_license_added_low_score.json') + old_scan = self.get_test_loc('cli/scan_modified_old_license_added_low_score.json') + + delta = DeltaCode(new_scan, old_scan) + result_file = self.get_temp_file('.csv') + cli.generate_csv(delta, result_file) + expected_file = self.get_test_loc('cli/modified_new_license_added_low_score.csv') + check_csvs(result_file, expected_file) diff --git a/tests/test_deltacode.py b/tests/test_deltacode.py index da4330a8..9d653884 100644 --- a/tests/test_deltacode.py +++ b/tests/test_deltacode.py @@ -367,6 +367,203 @@ def test_DeltaCode_None_paths(self): assert result.deltas == None + def test_Delta_license_diff_new_no_license_info(self): + new_file = models.File({'path': 'new/path.txt'}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 50.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'license change' + + def test_Delta_license_diff_old_no_license_info(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'mit', 'score': 50.0}]}) + old_file = models.File({'path': 'old/path.txt'}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'license change' + + def test_Delta_license_diff_single_diff_multiple_keys(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'gpl-2.0', 'score': 100.0}, {'key': 'mit', 'score':30.0}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 50.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'license change' + + def test_Delta_license_diff_no_diff_multiple_keys(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'mit', 'score': 75.0}, {'key': 'mit', 'score': 90.0}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 100.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'modified' + + def test_Delta_license_diff_no_diff_multiple_keys_low_score_new(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'mit', 'score': 75.0}, {'key': 'mit', 'score': 90.0}, {'key': 'gpl-2.0', 'score': 49.9}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 100.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'modified' + + def test_Delta_license_diff_no_diff_multiple_keys_low_score_old(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'mit', 'score': 75.0}, {'key': 'mit', 'score': 90.0}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 100.0}, {'key': 'gpl-2.0', 'score': 49.9}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'modified' + + def test_Delta_license_diff_single_diff(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'gpl-2.0', 'score': 70.0}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 80.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'license change' + + def test_Delta_license_diff_no_diff(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'mit', 'score': 95.0}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 95.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'modified' + + def test_Delta_license_diff_missing_diff_low_score_new(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'mit', 'score': 45.0}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 95.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'license change' + + def test_Delta_license_diff_missing_diff_low_score_old(self): + new_file = models.File({'path': 'new/path.txt', 'licenses': [{'key': 'mit', 'score': 95.0}]}) + old_file = models.File({'path': 'old/path.txt', 'licenses': [{'key': 'mit', 'score': 45.0}]}) + + result = deltacode.Delta(new_file, old_file, 'modified') + result.license_diff() + + assert result.category == 'license change' + + def test_Delta_license_diff_one_None(self): + file_obj = models.File({'path': 'fake/path.txt'}) + + first_None = deltacode.Delta(None, file_obj, 'removed') + second_None = deltacode.Delta(file_obj, None, 'added') + + first_None.license_diff() + second_None.license_diff() + + assert first_None.category == 'removed' + assert second_None.category == 'added' + + def test_Delta_license_diff_None_files(self): + delta = deltacode.Delta(None, None, None) + + result = delta.license_diff() + + assert result == None + + def test_DeltaCode_license_modified_low_score(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_license_added_low_score.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_license_added_low_score.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert len([i for i in deltas.get('modified') if i.category == 'license change']) == 0 + + def test_DeltaCode_license_modified(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_license_added.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_license_added.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert len([i for i in deltas.get('modified') if i.category == 'license change']) == 2 + assert len([i for i in deltas.get('modified') if i.category == 'modified']) == 1 + + def test_DeltaCode_no_license_key_value(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_no_license_key.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_no_license_key.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert len([i for i in deltas.get('modified') if i.category == 'license change']) == 0 + assert len([i for i in deltas.get('modified') if i.category == 'modified']) == 2 + + def test_DeltaCode_no_license_changes(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_no_license_changes.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_no_license_changes.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert len([i for i in deltas.get('modified') if i.category == 'license change']) == 0 + assert len([i for i in deltas.get('modified') if i.category == 'modified']) == 2 + + def test_Delta_to_dict_modified_license_added(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_license_added.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_license_added.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/a/a1.py'] == ['license change'] + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/b/b1.py'] == ['license change'] + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/c/c1.py'] == ['modified'] + + def test_Delta_to_dict_modified_license_added_low_score(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_license_added_low_score.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_license_added_low_score.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/a/a1.py'] == ['modified'] + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/b/b1.py'] == ['modified'] + + def test_Delta_to_dict_modified_no_license_changes(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_no_license_changes.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_no_license_changes.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/a/a1.py'] == ['modified'] + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/b/b1.py'] == ['modified'] + + def test_Delta_to_dict_modified_no_license_key(self): + new_scan = self.get_test_loc('deltacode/scan_modified_new_no_license_key.json') + old_scan = self.get_test_loc('deltacode/scan_modified_old_no_license_key.json') + + result = DeltaCode(new_scan, old_scan) + + deltas = result.deltas + + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/a/a1.py'] == ['modified'] + assert [d.to_dict().get('category') for d in deltas.get('modified') if d.to_dict().get('path') == 'some/path/b/b1.py'] == ['modified'] + def test_Delta_to_dict_removed(self): old = models.File({ 'path': 'path/removed.txt',