diff --git a/src/spdx_tools/spdx/parser/tagvalue/parser.py b/src/spdx_tools/spdx/parser/tagvalue/parser.py index 50096bda2..e03dd48f5 100644 --- a/src/spdx_tools/spdx/parser/tagvalue/parser.py +++ b/src/spdx_tools/spdx/parser/tagvalue/parser.py @@ -426,7 +426,15 @@ def p_pkg_verification_code(self, p): value = match.group(verif_code_code_grp) excluded_files = None if match.group(verif_code_exc_files_grp): - excluded_files = match.group(verif_code_exc_files_grp).split(",") + # The specification only ever shows one excluded file and does not say how + # several are separated. Accept both spellings in use: commas, which this + # parser has always split on, and whitespace, which is what our own + # tag-value writer emits. + excluded_files = [ + file_name + for file_name in re.split(r"[,\s]+", match.group(verif_code_exc_files_grp).strip()) + if file_name + ] or None self.current_element["verification_code"] = PackageVerificationCode(value, excluded_files) @grammar_rule("files_analyzed : PKG_FILES_ANALYZED LINE") diff --git a/tests/spdx/parser/tagvalue/test_package_parser.py b/tests/spdx/parser/tagvalue/test_package_parser.py index 470f1e2f7..d8ad678d3 100644 --- a/tests/spdx/parser/tagvalue/test_package_parser.py +++ b/tests/spdx/parser/tagvalue/test_package_parser.py @@ -138,3 +138,32 @@ def test_parse_invalid_package(package_str, expected_message): parser.parse(package_str) assert expected_message in err.value.get_messages()[0] + + +@pytest.mark.parametrize( + "excludes_str, expected_excluded_files", + [ + # What our own tag-value writer emits. + ("./package.spdx ./excluded.txt", ["./package.spdx", "./excluded.txt"]), + # What this parser has always split on. + ("./package.spdx,./excluded.txt", ["./package.spdx", "./excluded.txt"]), + ("./package.spdx, ./excluded.txt", ["./package.spdx", "./excluded.txt"]), + ("./package.spdx", ["./package.spdx"]), + ], +) +def test_parse_package_verification_code_excluded_files(excludes_str, expected_excluded_files): + parser = Parser() + package_str = "\n".join( + [ + "PackageName: Test", + "SPDXID: SPDXRef-Package", + "PackageDownloadLocation: http://example.com/test", + f"PackageVerificationCode: d6a770ba38583ed4bb4525bd96e50461655d2758 (excludes: {excludes_str})", + ] + ) + document = parser.parse("\n".join([DOCUMENT_STR, package_str])) + + assert document is not None + verification_code = document.packages[0].verification_code + assert verification_code.value == "d6a770ba38583ed4bb4525bd96e50461655d2758" + assert verification_code.excluded_files == expected_excluded_files diff --git a/tests/spdx/writer/tagvalue/test_tagvalue_writer.py b/tests/spdx/writer/tagvalue/test_tagvalue_writer.py index 487ee0dca..bba872dd8 100644 --- a/tests/spdx/writer/tagvalue/test_tagvalue_writer.py +++ b/tests/spdx/writer/tagvalue/test_tagvalue_writer.py @@ -23,7 +23,12 @@ ) from spdx_tools.spdx.parser.tagvalue import tagvalue_parser from spdx_tools.spdx.writer.tagvalue.tagvalue_writer import write_document, write_document_to_file -from tests.spdx.fixtures import checksum_fixture, document_fixture +from tests.spdx.fixtures import ( + checksum_fixture, + document_fixture, + package_fixture, + package_verification_code_fixture, +) @pytest.fixture @@ -43,6 +48,23 @@ def test_write_tag_value(temporary_file_path: str): assert parsed_document == document +def test_write_tag_value_with_several_excluded_files(temporary_file_path: str): + """The writer joins the excluded files with a space, so the parser has to read + them back the same way. With one excluded file, which is all the specification + shows and all the fixture has, the two agree by accident.""" + excluded_files = ["./package.spdx", "./excluded.txt", "./third.bin"] + document = document_fixture( + packages=[package_fixture(verification_code=package_verification_code_fixture(excluded_files=excluded_files))] + ) + + write_document_to_file(document, temporary_file_path, False) + + parsed_document = tagvalue_parser.parse_from_file(temporary_file_path) + + assert parsed_document.packages[0].verification_code.excluded_files == excluded_files + assert parsed_document == document + + def test_correct_order_of_elements(): packages = [ Package(name="Test Package A", spdx_id="SPDXRef-Package-A", download_location=""),