1// SPDX-FileCopyrightText: 2020-2021 HH Partners
2//
3// SPDX-License-Identifier: MIT
4
5use serde::{Deserialize, Serialize};
6use strum_macros::AsRefStr;
7
8/// <https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/#71-relationship>
9#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Eq, Hash)]
10#[serde(rename_all = "camelCase")]
11pub struct Relationship {
12 /// SPDX ID of the element.
13 pub spdx_element_id: String,
14
15 /// SPDX ID of the related element.
16 pub related_spdx_element: String,
17
18 /// Type of the relationship.
19 pub relationship_type: RelationshipType,
20
21 /// <https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/#72-relationship-comment>
22 #[serde(skip_serializing_if = "Option::is_none")]
23 #[serde(default)]
24 pub comment: Option<String>,
25}
26
27impl Relationship {
28 /// Create a new relationship.
29 pub fn new(
30 spdx_element_id: &str,
31 related_spdx_element: &str,
32 relationship_type: RelationshipType,
33 comment: Option<String>,
34 ) -> Self {
35 Self {
36 spdx_element_id: spdx_element_id.to_string(),
37 related_spdx_element: related_spdx_element.to_string(),
38 relationship_type,
39 comment,
40 }
41 }
42}
43
44/// <https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/#71-relationship>
45#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, AsRefStr, Eq, Hash)]
46#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
47pub enum RelationshipType {
48 Describes,
49 DescribedBy,
50 Contains,
51 ContainedBy,
52 DependsOn,
53 DependencyOf,
54 DependencyManifestOf,
55 BuildDependencyOf,
56 DevDependencyOf,
57 OptionalDependencyOf,
58 ProvidedDependencyOf,
59 TestDependencyOf,
60 RuntimeDependencyOf,
61 ExampleOf,
62 Generates,
63 GeneratedFrom,
64 AncestorOf,
65 DescendantOf,
66 VariantOf,
67 DistributionArtifact,
68 PatchFor,
69 PatchApplied,
70 CopyOf,
71 FileAdded,
72 FileDeleted,
73 FileModified,
74 ExpandedFromArchive,
75 DynamicLink,
76 StaticLink,
77 DataFileOf,
78 TestCaseOf,
79 BuildToolOf,
80 DevToolOf,
81 TestOf,
82 TestToolOf,
83 DocumentationOf,
84 OptionalComponentOf,
85 MetafileOf,
86 PackageOf,
87 Amends,
88 PrerequisiteFor,
89 HasPrerequisite,
90 RequirementDescriptionFor,
91 SpecificationFor,
92 Other,
93}
94
95#[cfg(test)]
96mod test {
97 use std::fs::read_to_string;
98
99 use crate::models::SPDX;
100
101 use super::*;
102
103 #[test]
104 fn spdx_element_id() {
105 let spdx: SPDX = serde_json::from_str(
106 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
107 )
108 .unwrap();
109 assert_eq!(
110 spdx.relationships[0].spdx_element_id,
111 "SPDXRef-DOCUMENT".to_string()
112 );
113 }
114 #[test]
115 fn related_spdx_element() {
116 let spdx: SPDX = serde_json::from_str(
117 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
118 )
119 .unwrap();
120 assert_eq!(
121 spdx.relationships[0].related_spdx_element,
122 "SPDXRef-Package".to_string()
123 );
124 }
125 #[test]
126 fn relationship_type() {
127 let spdx: SPDX = serde_json::from_str(
128 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
129 )
130 .unwrap();
131 assert_eq!(
132 spdx.relationships[0].relationship_type,
133 RelationshipType::Contains
134 );
135 assert_eq!(
136 spdx.relationships[2].relationship_type,
137 RelationshipType::CopyOf
138 );
139 }
140}
141