Skip to content

Commit f481c16

Browse files
[issue-692] add test for the example code
Signed-off-by: Armin Tänzer <armin.taenzer@tngtech.com>
1 parent 7857850 commit f481c16

2 files changed

Lines changed: 149 additions & 0 deletions

File tree

tests/spdx/examples/__init__.py

Whitespace-only changes.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# SPDX-FileCopyrightText: 2023 spdx contributors
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
import logging
5+
from datetime import datetime
6+
from typing import List
7+
8+
from license_expression import get_spdx_licensing
9+
10+
from spdx_tools.spdx.model import (
11+
Actor,
12+
ActorType,
13+
Checksum,
14+
ChecksumAlgorithm,
15+
CreationInfo,
16+
Document,
17+
ExternalPackageRef,
18+
ExternalPackageRefCategory,
19+
File,
20+
FileType,
21+
Package,
22+
PackagePurpose,
23+
PackageVerificationCode,
24+
Relationship,
25+
RelationshipType,
26+
)
27+
from spdx_tools.spdx.validation.document_validator import validate_full_spdx_document
28+
from spdx_tools.spdx.validation.validation_message import ValidationMessage
29+
30+
# This example shows how to use the spdx-tools to create an SPDX document from scratch,
31+
# validate it and write it to a file.
32+
33+
34+
def test_spdx2_document_from_scratch():
35+
# First up, we need general information about the creation of the document, summarised by the CreationInfo class.
36+
creation_info = CreationInfo(
37+
spdx_version="SPDX-2.3",
38+
spdx_id="SPDXRef-DOCUMENT",
39+
name="document name",
40+
data_license="CC0-1.0",
41+
document_namespace="https://some.namespace",
42+
creators=[Actor(ActorType.PERSON, "Jane Doe", "jane.doe@example.com")],
43+
created=datetime(2022, 1, 1),
44+
)
45+
46+
# creation_info is the only required property of the Document class (have a look there!),
47+
# the rest are optional lists.
48+
# So, we are set up to create a new document instance.
49+
document = Document(creation_info)
50+
51+
# The document currently does not describe anything. Let's create a package that we can add to it.
52+
# The Package class has quite a few properties (have a look there!),
53+
# but only name, spdx_id and download_location are mandatory in SPDX v2.3.
54+
package = Package(
55+
name="package name",
56+
spdx_id="SPDXRef-Package",
57+
download_location="https://download.com",
58+
version="2.2.1",
59+
file_name="./foo.bar",
60+
supplier=Actor(ActorType.PERSON, "Jane Doe", "jane.doe@example.com"),
61+
originator=Actor(ActorType.ORGANIZATION, "some organization", "contact@example.com"),
62+
files_analyzed=True,
63+
verification_code=PackageVerificationCode(
64+
value="d6a770ba38583ed4bb4525bd96e50461655d2758", excluded_files=["./some.file"]
65+
),
66+
checksums=[
67+
Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2758"),
68+
Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"),
69+
],
70+
license_concluded=get_spdx_licensing().parse("GPL-2.0-only OR MIT"),
71+
license_info_from_files=[get_spdx_licensing().parse("GPL-2.0-only"), get_spdx_licensing().parse("MIT")],
72+
license_declared=get_spdx_licensing().parse("GPL-2.0-only AND MIT"),
73+
license_comment="license comment",
74+
copyright_text="Copyright 2022 Jane Doe",
75+
description="package description",
76+
attribution_texts=["package attribution"],
77+
primary_package_purpose=PackagePurpose.LIBRARY,
78+
release_date=datetime(2015, 1, 1),
79+
external_references=[
80+
ExternalPackageRef(
81+
category=ExternalPackageRefCategory.OTHER,
82+
reference_type="http://reference.type",
83+
locator="reference/locator",
84+
comment="external reference comment",
85+
)
86+
],
87+
)
88+
89+
# Now that we have a package defined, we can add it to the document's package property.
90+
document.packages = [package]
91+
92+
# A DESCRIBES relationship asserts that the document indeed describes the package.
93+
describes_relationship = Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-Package")
94+
document.relationships = [describes_relationship]
95+
96+
# Let's add two files. Have a look at the file class for all possible properties a file can have.
97+
file1 = File(
98+
name="./package/file1.py",
99+
spdx_id="SPDXRef-File1",
100+
file_types=[FileType.SOURCE],
101+
checksums=[
102+
Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2758"),
103+
Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"),
104+
],
105+
license_concluded=get_spdx_licensing().parse("MIT"),
106+
license_info_in_file=[get_spdx_licensing().parse("MIT")],
107+
copyright_text="Copyright 2022 Jane Doe",
108+
)
109+
file2 = File(
110+
name="./package/file2.py",
111+
spdx_id="SPDXRef-File2",
112+
checksums=[
113+
Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2759"),
114+
],
115+
license_concluded=get_spdx_licensing().parse("GPL-2.0-only"),
116+
)
117+
118+
# Assuming the package contains those two files, we create two CONTAINS relationships.
119+
contains_relationship1 = Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File1")
120+
contains_relationship2 = Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File2")
121+
122+
# This library uses run-time type checks when assigning properties.
123+
# Because in-place alterations like .append() circumvent these checks, we don't use them here.
124+
document.relationships += [contains_relationship1, contains_relationship2]
125+
document.files += [file1, file2]
126+
127+
# We now have created a document with basic creation information, describing a package that contains two files.
128+
# You can also add Annotations, Snippets and ExtractedLicensingInfo
129+
# to the document in an analogous manner to the above.
130+
# Have a look at their respective classes if you are unsure about their properties.
131+
assert len(document.packages) == 1
132+
assert len(document.files) == 2
133+
assert len(document.relationships) == 3
134+
assert len(document.snippets) == 0
135+
assert len(document.annotations) == 0
136+
assert len(document.extracted_licensing_info) == 0
137+
138+
# This library provides comprehensive validation against the SPDX specification.
139+
# Note that details of the validation depend on the SPDX version of the document.
140+
validation_messages: List[ValidationMessage] = validate_full_spdx_document(document)
141+
142+
# You can have a look at each entry's message and context (like spdx_id, parent_id, full_element)
143+
# which will help you pinpoint the location of the invalidity.
144+
for message in validation_messages:
145+
logging.warning(message.validation_message)
146+
logging.warning(message.context)
147+
148+
# If the document is valid, validation_messages will be empty.
149+
assert validation_messages == []

0 commit comments

Comments
 (0)