diff --git a/AUTHORS.rst b/AUTHORS.rst
index 9a8224dc7da..1d29e439e4b 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -108,3 +108,5 @@ The following organizations or individuals have contributed to ScanCode:
- Yash Sharma @yasharmaster
- Yunus Rahbar @yns88
- Stefano Zacchiroli @zacchiro
+- Temi Eyesan @teyesan
+- Tram Trinh @tram-tr
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index d9a5a6b4026..fc373bcb38a 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -8,6 +8,11 @@ Next release
``licensedcode-data``.
https://github.com/aboutcode-org/scancode-toolkit/pull/5056
+- Fixed nuget/nuspec parser to correctly extract file-referenced and
+ expression-based elements instead of the deprecated
+ licenseUrl fallback
+ https://github.com/aboutcode-org/scancode-toolkit/pull/5271
+
v33.0.0rc1 - 2026-05-14
------------------------
diff --git a/src/packagedcode/nuget.py b/src/packagedcode/nuget.py
index d0d7e110f2f..72a8521e482 100644
--- a/src/packagedcode/nuget.py
+++ b/src/packagedcode/nuget.py
@@ -18,6 +18,8 @@
Handle NuGet packages and their manifests.
"""
+DEPRECATED_NUGET_LICENSE_URL = 'https://aka.ms/deprecateLicenseUrl'
+
def get_dependencies(nuspec):
"""
@@ -79,6 +81,32 @@ def _get_dep_packs(deps, extra_data):
extra_data=extra,
)
+def get_declared_license(nuspec):
+ extracted_license_statement = None
+ license_file = None
+
+ license_data = nuspec.get('license')
+ if license_data:
+ if isinstance(license_data, dict):
+ license_type = license_data.get('@type')
+ license_text = license_data.get('#text')
+ if license_type == 'file':
+ license_file = license_text
+ else:
+ # "expression" (an SPDX license expression) or any other unspecified type: keep the text as is
+ extracted_license_statement = license_text
+ else:
+ # defensive: in case a plain string ever shows up here.
+ extracted_license_statement = license_data
+
+ license_url = nuspec.get('licenseUrl')
+ if license_url and license_url != DEPRECATED_NUGET_LICENSE_URL:
+ if extracted_license_statement:
+ extracted_license_statement = f'{extracted_license_statement}\n{license_url}'
+ else:
+ extracted_license_statement = license_url
+
+ return extracted_license_statement, license_file
def get_urls(name, version, **kwargs):
return dict(
@@ -155,14 +183,20 @@ def parse(cls, location, package_only=False):
urls = get_urls(name, version)
- extracted_license_statement = None
- # See https://docs.microsoft.com/en-us/nuget/reference/nuspec#license
- # This is a SPDX license expression
- if 'license' in nuspec:
- extracted_license_statement = nuspec.get('license')
- # Deprecated and not a license expression, just a URL
- elif 'licenseUrl' in nuspec:
- extracted_license_statement = nuspec.get('licenseUrl')
+ # extracted_license_statement = None
+ # # See https://docs.microsoft.com/en-us/nuget/reference/nuspec#license
+ # # This is a SPDX license expression
+ # if 'license' in nuspec:
+ # extracted_license_statement = nuspec.get('license')
+ # # Deprecated and not a license expression, just a URL
+ # elif 'licenseUrl' in nuspec:
+ # extracted_license_statement = nuspec.get('licenseUrl')
+
+ extracted_license_statement, license_file = get_declared_license(nuspec)
+ extra_data = {}
+ if license_file:
+ extra_data['license_file'] = license_file
+
package_data = dict(
datasource_id=cls.datasource_id,
@@ -176,6 +210,7 @@ def parse(cls, location, package_only=False):
extracted_license_statement=extracted_license_statement,
copyright=nuspec.get('copyright') or None,
vcs_url=vcs_url,
+ extra_data=extra_data,
**urls,
)
yield models.PackageData.from_data(package_data, package_only)
diff --git a/tests/packagedcode/data/license_detection/reference-at-manifest/fizzler.expected.json b/tests/packagedcode/data/license_detection/reference-at-manifest/fizzler.expected.json
index e3cfae03ae4..8b1d34f55bd 100644
--- a/tests/packagedcode/data/license_detection/reference-at-manifest/fizzler.expected.json
+++ b/tests/packagedcode/data/license_detection/reference-at-manifest/fizzler.expected.json
@@ -43,16 +43,17 @@
"license_expression": "unknown-license-reference",
"license_expression_spdx": "LicenseRef-scancode-unknown-license-reference",
"from_file": "fizzler/Fizzler.nuspec",
- "start_line": 1,
- "end_line": 1,
- "matcher": "1-hash",
- "score": 16.0,
- "matched_length": 3,
+ "start_line": 9,
+ "end_line": 9,
+ "matcher": "2-aho",
+ "score": 33.0,
+ "matched_length": 6,
"match_coverage": 100.0,
- "rule_relevance": 16,
- "rule_identifier": "unknown-license-reference_383.RULE",
- "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/unknown-license-reference_383.RULE",
- "matched_text": "license COPYING.txt"
+ "rule_relevance": 33,
+ "rule_identifier": "unknown-license-reference_382.RULE",
+ "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/unknown-license-reference_382.RULE",
+ "matched_text": " COPYING.txt",
+ "matched_text_diagnostics": "license type=\"file\">COPYING.txt"
},
{
"license_expression": "lgpl-2.1-plus",
@@ -87,21 +88,23 @@
"matched_text_diagnostics": "LICENSE\n \nGNU GENERAL PUBLIC LICENSE"
}
],
- "identifier": "lgpl_2_1_plus_and_gpl_1_0_plus-15b4d27c-9fa6-eb84-010f-152d45207f46",
"detection_log": [
"package-unknown-reference-to-local-file"
- ]
+ ],
+ "identifier": "lgpl_2_1_plus_and_gpl_1_0_plus-62bd07da-4dc9-fb2e-ad66-9eafe419c120"
}
],
"other_license_expression": null,
"other_license_expression_spdx": null,
"other_license_detections": [],
- "extracted_license_statement": "'@type': file\n'#text': COPYING.txt\n",
+ "extracted_license_statement": null,
"notice_text": null,
"source_packages": [],
"is_private": false,
"is_virtual": false,
- "extra_data": {},
+ "extra_data": {
+ "license_file": "COPYING.txt"
+ },
"repository_homepage_url": "https://www.nuget.org/packages/Fizzler/1.3.0",
"repository_download_url": "https://www.nuget.org/api/v2/package/Fizzler/1.3.0",
"api_data_url": "https://api.nuget.org/v3/registration3/fizzler/1.3.0.json",
@@ -154,71 +157,13 @@
}
],
"license_detections": [
- {
- "identifier": "lgpl_2_1_plus_and_gpl_1_0_plus-15b4d27c-9fa6-eb84-010f-152d45207f46",
- "license_expression": "lgpl-2.1-plus AND gpl-1.0-plus",
- "license_expression_spdx": "LGPL-2.1-or-later AND GPL-1.0-or-later",
- "detection_count": 1,
- "detection_log": [
- "package-unknown-reference-to-local-file"
- ],
- "reference_matches": [
- {
- "license_expression": "unknown-license-reference",
- "license_expression_spdx": "LicenseRef-scancode-unknown-license-reference",
- "from_file": "fizzler/Fizzler.nuspec",
- "start_line": 1,
- "end_line": 1,
- "matcher": "1-hash",
- "score": 16.0,
- "matched_length": 3,
- "match_coverage": 100.0,
- "rule_relevance": 16,
- "rule_identifier": "unknown-license-reference_383.RULE",
- "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/unknown-license-reference_383.RULE",
- "matched_text": "license COPYING.txt"
- },
- {
- "license_expression": "lgpl-2.1-plus",
- "license_expression_spdx": "LGPL-2.1-or-later",
- "from_file": "fizzler/COPYING.txt",
- "start_line": 1,
- "end_line": 1,
- "matcher": "2-aho",
- "score": 100.0,
- "matched_length": 5,
- "match_coverage": 100.0,
- "rule_relevance": 100,
- "rule_identifier": "lgpl-2.1-plus_485.RULE",
- "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/lgpl-2.1-plus_485.RULE",
- "matched_text": "GNU LESSER GENERAL PUBLIC LICENSE",
- "matched_text_diagnostics": "GNU LESSER GENERAL PUBLIC LICENSE"
- },
- {
- "license_expression": "gpl-1.0-plus",
- "license_expression_spdx": "GPL-1.0-or-later",
- "from_file": "fizzler/COPYING.txt",
- "start_line": 1,
- "end_line": 3,
- "matcher": "2-aho",
- "score": 100.0,
- "matched_length": 5,
- "match_coverage": 100.0,
- "rule_relevance": 100,
- "rule_identifier": "gpl_160.RULE",
- "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/gpl_160.RULE",
- "matched_text": "GNU LESSER GENERAL PUBLIC LICENSE\n \nGNU GENERAL PUBLIC LICENSE",
- "matched_text_diagnostics": "LICENSE\n \nGNU GENERAL PUBLIC LICENSE"
- }
- ]
- },
{
"identifier": "lgpl_2_1_plus_and_gpl_1_0_plus-62bd07da-4dc9-fb2e-ad66-9eafe419c120",
"license_expression": "lgpl-2.1-plus AND gpl-1.0-plus",
"license_expression_spdx": "LGPL-2.1-or-later AND GPL-1.0-or-later",
- "detection_count": 1,
+ "detection_count": 2,
"detection_log": [
- "unknown-reference-to-local-file"
+ "package-unknown-reference-to-local-file"
],
"reference_matches": [
{
@@ -414,16 +359,17 @@
"license_expression": "unknown-license-reference",
"license_expression_spdx": "LicenseRef-scancode-unknown-license-reference",
"from_file": "fizzler/Fizzler.nuspec",
- "start_line": 1,
- "end_line": 1,
- "matcher": "1-hash",
- "score": 16.0,
- "matched_length": 3,
+ "start_line": 9,
+ "end_line": 9,
+ "matcher": "2-aho",
+ "score": 33.0,
+ "matched_length": 6,
"match_coverage": 100.0,
- "rule_relevance": 16,
- "rule_identifier": "unknown-license-reference_383.RULE",
- "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/unknown-license-reference_383.RULE",
- "matched_text": "license COPYING.txt"
+ "rule_relevance": 33,
+ "rule_identifier": "unknown-license-reference_382.RULE",
+ "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/unknown-license-reference_382.RULE",
+ "matched_text": " COPYING.txt",
+ "matched_text_diagnostics": "license type=\"file\">COPYING.txt"
},
{
"license_expression": "lgpl-2.1-plus",
@@ -458,22 +404,24 @@
"matched_text_diagnostics": "LICENSE\n \nGNU GENERAL PUBLIC LICENSE"
}
],
- "identifier": "lgpl_2_1_plus_and_gpl_1_0_plus-15b4d27c-9fa6-eb84-010f-152d45207f46",
"detection_log": [
"package-unknown-reference-to-local-file"
- ]
+ ],
+ "identifier": "lgpl_2_1_plus_and_gpl_1_0_plus-62bd07da-4dc9-fb2e-ad66-9eafe419c120"
}
],
"other_license_expression": null,
"other_license_expression_spdx": null,
"other_license_detections": [],
- "extracted_license_statement": "'@type': file\n'#text': COPYING.txt\n",
+ "extracted_license_statement": null,
"notice_text": null,
"source_packages": [],
"file_references": [],
"is_private": false,
"is_virtual": false,
- "extra_data": {},
+ "extra_data": {
+ "license_file": "COPYING.txt"
+ },
"dependencies": [
{
"purl": "pkg:nuget/NETStandard.Library",
@@ -514,8 +462,8 @@
"for_packages": [
"pkg:nuget/Fizzler@1.3.0?uuid=fixed-uid-done-for-testing-5642512d1758"
],
- "detected_license_expression": "lgpl-2.1-plus AND gpl-1.0-plus",
- "detected_license_expression_spdx": "LGPL-2.1-or-later AND GPL-1.0-or-later",
+ "detected_license_expression": "unknown-license-reference",
+ "detected_license_expression_spdx": "LicenseRef-scancode-unknown-license-reference",
"license_detections": [
{
"license_expression": "lgpl-2.1-plus AND gpl-1.0-plus",
@@ -571,7 +519,7 @@
}
],
"detection_log": [
- "unknown-reference-to-local-file"
+ "package-unknown-reference-to-local-file"
],
"identifier": "lgpl_2_1_plus_and_gpl_1_0_plus-62bd07da-4dc9-fb2e-ad66-9eafe419c120"
}
diff --git a/tests/packagedcode/data/nuget/ExpressionLicense.nuspec b/tests/packagedcode/data/nuget/ExpressionLicense.nuspec
new file mode 100644
index 00000000000..14c253ebb26
--- /dev/null
+++ b/tests/packagedcode/data/nuget/ExpressionLicense.nuspec
@@ -0,0 +1,9 @@
+
+
+
+ ExpressionLicenseExample
+ 1.0.0
+ false
+ MIT
+
+
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/ExpressionLicense.nuspec.json.expected b/tests/packagedcode/data/nuget/ExpressionLicense.nuspec.json.expected
new file mode 100644
index 00000000000..c63a64d19dc
--- /dev/null
+++ b/tests/packagedcode/data/nuget/ExpressionLicense.nuspec.json.expected
@@ -0,0 +1,69 @@
+[
+ {
+ "type": "nuget",
+ "namespace": null,
+ "name": "ExpressionLicenseExample",
+ "version": "1.0.0",
+ "qualifiers": {},
+ "subpath": null,
+ "primary_language": null,
+ "description": null,
+ "release_date": null,
+ "parties": [],
+ "keywords": [],
+ "homepage_url": null,
+ "download_url": null,
+ "size": null,
+ "sha1": null,
+ "md5": null,
+ "sha256": null,
+ "sha512": null,
+ "bug_tracking_url": null,
+ "code_view_url": null,
+ "vcs_url": null,
+ "copyright": null,
+ "holder": null,
+ "declared_license_expression": "mit",
+ "declared_license_expression_spdx": "MIT",
+ "license_detections": [
+ {
+ "license_expression": "mit",
+ "license_expression_spdx": "MIT",
+ "matches": [
+ {
+ "license_expression": "mit",
+ "license_expression_spdx": "MIT",
+ "from_file": null,
+ "start_line": 1,
+ "end_line": 1,
+ "matcher": "1-spdx-id",
+ "score": 100.0,
+ "matched_length": 1,
+ "match_coverage": 100.0,
+ "rule_relevance": 100,
+ "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06",
+ "rule_url": null,
+ "matched_text": "MIT"
+ }
+ ],
+ "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf"
+ }
+ ],
+ "other_license_expression": null,
+ "other_license_expression_spdx": null,
+ "other_license_detections": [],
+ "extracted_license_statement": "MIT",
+ "notice_text": null,
+ "source_packages": [],
+ "file_references": [],
+ "is_private": false,
+ "is_virtual": false,
+ "extra_data": {},
+ "dependencies": [],
+ "repository_homepage_url": "https://www.nuget.org/packages/ExpressionLicenseExample/1.0.0",
+ "repository_download_url": "https://www.nuget.org/api/v2/package/ExpressionLicenseExample/1.0.0",
+ "api_data_url": "https://api.nuget.org/v3/registration3/expressionlicenseexample/1.0.0.json",
+ "datasource_id": "nuget_nupsec",
+ "purl": "pkg:nuget/ExpressionLicenseExample@1.0.0"
+ }
+]
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/LicenseURLOnly.nuspec b/tests/packagedcode/data/nuget/LicenseURLOnly.nuspec
new file mode 100644
index 00000000000..14cd7e0b4d4
--- /dev/null
+++ b/tests/packagedcode/data/nuget/LicenseURLOnly.nuspec
@@ -0,0 +1,9 @@
+
+
+
+ LicenseUrlOnlyExample
+ 1.0.0
+ false
+ https://opensource.org/licenses/MIT
+
+
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/LicenseURLOnly.nuspec.json.expected b/tests/packagedcode/data/nuget/LicenseURLOnly.nuspec.json.expected
new file mode 100644
index 00000000000..a1804e7c03f
--- /dev/null
+++ b/tests/packagedcode/data/nuget/LicenseURLOnly.nuspec.json.expected
@@ -0,0 +1,69 @@
+[
+ {
+ "type": "nuget",
+ "namespace": null,
+ "name": "LicenseUrlOnlyExample",
+ "version": "1.0.0",
+ "qualifiers": {},
+ "subpath": null,
+ "primary_language": null,
+ "description": null,
+ "release_date": null,
+ "parties": [],
+ "keywords": [],
+ "homepage_url": null,
+ "download_url": null,
+ "size": null,
+ "sha1": null,
+ "md5": null,
+ "sha256": null,
+ "sha512": null,
+ "bug_tracking_url": null,
+ "code_view_url": null,
+ "vcs_url": null,
+ "copyright": null,
+ "holder": null,
+ "declared_license_expression": "mit",
+ "declared_license_expression_spdx": "MIT",
+ "license_detections": [
+ {
+ "license_expression": "mit",
+ "license_expression_spdx": "MIT",
+ "matches": [
+ {
+ "license_expression": "mit",
+ "license_expression_spdx": "MIT",
+ "from_file": null,
+ "start_line": 1,
+ "end_line": 1,
+ "matcher": "1-hash",
+ "score": 100.0,
+ "matched_length": 5,
+ "match_coverage": 100.0,
+ "rule_relevance": 100,
+ "rule_identifier": "mit_65.RULE",
+ "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_65.RULE",
+ "matched_text": "https://opensource.org/licenses/MIT"
+ }
+ ],
+ "identifier": "mit-8c45a313-6646-a283-ebeb-697e96d45185"
+ }
+ ],
+ "other_license_expression": null,
+ "other_license_expression_spdx": null,
+ "other_license_detections": [],
+ "extracted_license_statement": "https://opensource.org/licenses/MIT",
+ "notice_text": null,
+ "source_packages": [],
+ "file_references": [],
+ "is_private": false,
+ "is_virtual": false,
+ "extra_data": {},
+ "dependencies": [],
+ "repository_homepage_url": "https://www.nuget.org/packages/LicenseUrlOnlyExample/1.0.0",
+ "repository_download_url": "https://www.nuget.org/api/v2/package/LicenseUrlOnlyExample/1.0.0",
+ "api_data_url": "https://api.nuget.org/v3/registration3/licenseurlonlyexample/1.0.0.json",
+ "datasource_id": "nuget_nupsec",
+ "purl": "pkg:nuget/LicenseUrlOnlyExample@1.0.0"
+ }
+]
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/NoLicenseInfo.nuspec b/tests/packagedcode/data/nuget/NoLicenseInfo.nuspec
new file mode 100644
index 00000000000..ab5abcca401
--- /dev/null
+++ b/tests/packagedcode/data/nuget/NoLicenseInfo.nuspec
@@ -0,0 +1,8 @@
+
+
+
+ NoLicenseInfoExample
+ 1.0.0
+ false
+
+
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/NoLicenseInfo.nuspec.json.expected b/tests/packagedcode/data/nuget/NoLicenseInfo.nuspec.json.expected
new file mode 100644
index 00000000000..a74a297a063
--- /dev/null
+++ b/tests/packagedcode/data/nuget/NoLicenseInfo.nuspec.json.expected
@@ -0,0 +1,46 @@
+[
+ {
+ "type": "nuget",
+ "namespace": null,
+ "name": "NoLicenseInfoExample",
+ "version": "1.0.0",
+ "qualifiers": {},
+ "subpath": null,
+ "primary_language": null,
+ "description": null,
+ "release_date": null,
+ "parties": [],
+ "keywords": [],
+ "homepage_url": null,
+ "download_url": null,
+ "size": null,
+ "sha1": null,
+ "md5": null,
+ "sha256": null,
+ "sha512": null,
+ "bug_tracking_url": null,
+ "code_view_url": null,
+ "vcs_url": null,
+ "copyright": null,
+ "holder": null,
+ "declared_license_expression": null,
+ "declared_license_expression_spdx": null,
+ "license_detections": [],
+ "other_license_expression": null,
+ "other_license_expression_spdx": null,
+ "other_license_detections": [],
+ "extracted_license_statement": null,
+ "notice_text": null,
+ "source_packages": [],
+ "file_references": [],
+ "is_private": false,
+ "is_virtual": false,
+ "extra_data": {},
+ "dependencies": [],
+ "repository_homepage_url": "https://www.nuget.org/packages/NoLicenseInfoExample/1.0.0",
+ "repository_download_url": "https://www.nuget.org/api/v2/package/NoLicenseInfoExample/1.0.0",
+ "api_data_url": "https://api.nuget.org/v3/registration3/nolicenseinfoexample/1.0.0.json",
+ "datasource_id": "nuget_nupsec",
+ "purl": "pkg:nuget/NoLicenseInfoExample@1.0.0"
+ }
+]
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/PlainLicense.nuspec b/tests/packagedcode/data/nuget/PlainLicense.nuspec
new file mode 100644
index 00000000000..3993bdd7fec
--- /dev/null
+++ b/tests/packagedcode/data/nuget/PlainLicense.nuspec
@@ -0,0 +1,9 @@
+
+
+
+ PlainLicenseExample
+ 1.0.0
+ false
+ MIT
+
+
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/PlainLicense.nuspec.json.expected b/tests/packagedcode/data/nuget/PlainLicense.nuspec.json.expected
new file mode 100644
index 00000000000..05366edcadf
--- /dev/null
+++ b/tests/packagedcode/data/nuget/PlainLicense.nuspec.json.expected
@@ -0,0 +1,69 @@
+[
+ {
+ "type": "nuget",
+ "namespace": null,
+ "name": "PlainLicenseExample",
+ "version": "1.0.0",
+ "qualifiers": {},
+ "subpath": null,
+ "primary_language": null,
+ "description": null,
+ "release_date": null,
+ "parties": [],
+ "keywords": [],
+ "homepage_url": null,
+ "download_url": null,
+ "size": null,
+ "sha1": null,
+ "md5": null,
+ "sha256": null,
+ "sha512": null,
+ "bug_tracking_url": null,
+ "code_view_url": null,
+ "vcs_url": null,
+ "copyright": null,
+ "holder": null,
+ "declared_license_expression": "mit",
+ "declared_license_expression_spdx": "MIT",
+ "license_detections": [
+ {
+ "license_expression": "mit",
+ "license_expression_spdx": "MIT",
+ "matches": [
+ {
+ "license_expression": "mit",
+ "license_expression_spdx": "MIT",
+ "from_file": null,
+ "start_line": 1,
+ "end_line": 1,
+ "matcher": "1-spdx-id",
+ "score": 100.0,
+ "matched_length": 1,
+ "match_coverage": 100.0,
+ "rule_relevance": 100,
+ "rule_identifier": "spdx-license-identifier-mit-5da48780aba670b0860c46d899ed42a0f243ff06",
+ "rule_url": null,
+ "matched_text": "MIT"
+ }
+ ],
+ "identifier": "mit-a822f434-d61f-f2b1-c792-8b8cb9e7b9bf"
+ }
+ ],
+ "other_license_expression": null,
+ "other_license_expression_spdx": null,
+ "other_license_detections": [],
+ "extracted_license_statement": "MIT",
+ "notice_text": null,
+ "source_packages": [],
+ "file_references": [],
+ "is_private": false,
+ "is_virtual": false,
+ "extra_data": {},
+ "dependencies": [],
+ "repository_homepage_url": "https://www.nuget.org/packages/PlainLicenseExample/1.0.0",
+ "repository_download_url": "https://www.nuget.org/api/v2/package/PlainLicenseExample/1.0.0",
+ "api_data_url": "https://api.nuget.org/v3/registration3/plainlicenseexample/1.0.0.json",
+ "datasource_id": "nuget_nupsec",
+ "purl": "pkg:nuget/PlainLicenseExample@1.0.0"
+ }
+]
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/SpecFlow.MsTest.nuspec b/tests/packagedcode/data/nuget/SpecFlow.MsTest.nuspec
new file mode 100644
index 00000000000..53018871859
--- /dev/null
+++ b/tests/packagedcode/data/nuget/SpecFlow.MsTest.nuspec
@@ -0,0 +1,22 @@
+
+
+
+ SpecFlow.MsTest
+ 3.1.89
+ SpecFlow
+ Tricentis
+ false
+ LICENSE.txt
+ https://aka.ms/deprecateLicenseUrl
+ https://specflow.org
+ Provides MsTest bindings for SpecFlow test execution
+ Copyright
+ specflow bdd mstest
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/packagedcode/data/nuget/SpecFlow.MsTest.nuspec.json.expected b/tests/packagedcode/data/nuget/SpecFlow.MsTest.nuspec.json.expected
new file mode 100644
index 00000000000..2c8eb2c8100
--- /dev/null
+++ b/tests/packagedcode/data/nuget/SpecFlow.MsTest.nuspec.json.expected
@@ -0,0 +1,92 @@
+[
+ {
+ "type": "nuget",
+ "namespace": null,
+ "name": "SpecFlow.MsTest",
+ "version": "3.1.89",
+ "qualifiers": {},
+ "subpath": null,
+ "primary_language": null,
+ "description": "Provides MsTest bindings for SpecFlow test execution",
+ "release_date": null,
+ "parties": [
+ {
+ "type": null,
+ "role": "author",
+ "name": "SpecFlow",
+ "email": null,
+ "url": null
+ },
+ {
+ "type": null,
+ "role": "owner",
+ "name": "Tricentis",
+ "email": null,
+ "url": null
+ }
+ ],
+ "keywords": [],
+ "homepage_url": "https://specflow.org",
+ "download_url": null,
+ "size": null,
+ "sha1": null,
+ "md5": null,
+ "sha256": null,
+ "sha512": null,
+ "bug_tracking_url": null,
+ "code_view_url": null,
+ "vcs_url": null,
+ "copyright": "Copyright",
+ "holder": "Copyright",
+ "declared_license_expression": null,
+ "declared_license_expression_spdx": null,
+ "license_detections": [],
+ "other_license_expression": null,
+ "other_license_expression_spdx": null,
+ "other_license_detections": [],
+ "extracted_license_statement": null,
+ "notice_text": null,
+ "source_packages": [],
+ "file_references": [],
+ "is_private": false,
+ "is_virtual": false,
+ "extra_data": {
+ "license_file": "LICENSE.txt"
+ },
+ "dependencies": [
+ {
+ "purl": "pkg:nuget/SpecFlow",
+ "extracted_requirement": "3.1.89",
+ "scope": "dependency",
+ "is_runtime": true,
+ "is_optional": false,
+ "is_pinned": false,
+ "is_direct": true,
+ "resolved_package": {},
+ "extra_data": {
+ "framework": ".NETStandard2.0",
+ "exclude": "Build,Analyzers"
+ }
+ },
+ {
+ "purl": "pkg:nuget/MSTest.TestFramework",
+ "extracted_requirement": "1.3.2",
+ "scope": "dependency",
+ "is_runtime": true,
+ "is_optional": false,
+ "is_pinned": false,
+ "is_direct": true,
+ "resolved_package": {},
+ "extra_data": {
+ "framework": ".NETStandard2.0",
+ "exclude": "Build,Analyzers"
+ }
+ }
+ ],
+ "repository_homepage_url": "https://www.nuget.org/packages/SpecFlow.MsTest/3.1.89",
+ "repository_download_url": "https://www.nuget.org/api/v2/package/SpecFlow.MsTest/3.1.89",
+ "api_data_url": "https://api.nuget.org/v3/registration3/specflow.mstest/3.1.89.json",
+ "datasource_id": "nuget_nupsec",
+ "purl": "pkg:nuget/SpecFlow.MsTest@3.1.89"
+ }
+]
\ No newline at end of file
diff --git a/tests/packagedcode/test_nuget.py b/tests/packagedcode/test_nuget.py
index d3af13ab51b..2e2b915a664 100644
--- a/tests/packagedcode/test_nuget.py
+++ b/tests/packagedcode/test_nuget.py
@@ -72,3 +72,33 @@ def test_parse_nuget_package_lock_json(self):
def test_package_lock_json_is_package_data_file(self):
test_file = self.get_test_loc('nuget/packages.lock.json')
assert nuget.NugetPackagesLockHandler.is_datafile(test_file)
+
+ def test_parse_creates_package_from_nuspec_plain_license(self):
+ test_file = self.get_test_loc('nuget/PlainLicense.nuspec')
+ package = nuget.NugetNuspecHandler.parse(test_file)
+ expected_loc = self.get_test_loc('nuget/PlainLicense.nuspec.json.expected')
+ self.check_packages_data(package, expected_loc, regen=REGEN_TEST_FIXTURES)
+
+ def test_parse_creates_package_from_nuspec_license_url_only(self):
+ test_file = self.get_test_loc('nuget/LicenseURLOnly.nuspec')
+ package = nuget.NugetNuspecHandler.parse(test_file)
+ expected_loc = self.get_test_loc('nuget/LicenseURLOnly.nuspec.json.expected')
+ self.check_packages_data(package, expected_loc, regen=REGEN_TEST_FIXTURES)
+
+ def test_parse_creates_package_from_nuspec_no_license_info(self):
+ test_file = self.get_test_loc('nuget/NoLicenseInfo.nuspec')
+ package = nuget.NugetNuspecHandler.parse(test_file)
+ expected_loc = self.get_test_loc('nuget/NoLicenseInfo.nuspec.json.expected')
+ self.check_packages_data(package, expected_loc, regen=REGEN_TEST_FIXTURES)
+
+ def test_parse_creates_package_from_nuspec_expression_license(self):
+ test_file = self.get_test_loc('nuget/ExpressionLicense.nuspec')
+ package = nuget.NugetNuspecHandler.parse(test_file)
+ expected_loc = self.get_test_loc('nuget/ExpressionLicense.nuspec.json.expected')
+ self.check_packages_data(package, expected_loc, regen=REGEN_TEST_FIXTURES)
+
+ def test_parse_creates_package_from_nuspec_with_license_file_and_deprecated_license_url(self):
+ test_file = self.get_test_loc('nuget/SpecFlow.MsTest.nuspec')
+ package = nuget.NugetNuspecHandler.parse(test_file)
+ expected_loc = self.get_test_loc('nuget/SpecFlow.MsTest.nuspec.json.expected')
+ self.check_packages_data(package, expected_loc, regen=REGEN_TEST_FIXTURES)