1 | // SPDX-FileCopyrightText: 2020-2021 HH Partners |
2 | // |
3 | // SPDX-License-Identifier: MIT |
4 | |
5 | use serde::{Deserialize, Serialize}; |
6 | use spdx_expression::SpdxExpression; |
7 | |
8 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/> |
9 | #[derive (Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] |
10 | pub struct Snippet { |
11 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#51-snippet-spdx-identifier> |
12 | #[serde(rename = "SPDXID" )] |
13 | pub snippet_spdx_identifier: String, |
14 | |
15 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#52-snippet-from-file-spdx-identifier> |
16 | #[serde(rename = "snippetFromFile" )] |
17 | pub snippet_from_file_spdx_identifier: String, |
18 | |
19 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#53-snippet-byte-range> |
20 | pub ranges: Vec<Range>, |
21 | |
22 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#55-snippet-concluded-license> |
23 | #[serde( |
24 | rename = "licenseConcluded" , |
25 | skip_serializing_if = "Option::is_none" , |
26 | default |
27 | )] |
28 | pub snippet_concluded_license: Option<SpdxExpression>, |
29 | |
30 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#56-license-information-in-snippet> |
31 | #[serde( |
32 | rename = "licenseInfoInSnippets" , |
33 | skip_serializing_if = "Vec::is_empty" , |
34 | default |
35 | )] |
36 | pub license_information_in_snippet: Vec<String>, |
37 | |
38 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#57-snippet-comments-on-license> |
39 | #[serde( |
40 | rename = "licenseComments" , |
41 | skip_serializing_if = "Option::is_none" , |
42 | default |
43 | )] |
44 | pub snippet_comments_on_license: Option<String>, |
45 | |
46 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#58-snippet-copyright-text> |
47 | #[serde( |
48 | rename = "copyrightText" , |
49 | skip_serializing_if = "Option::is_none" , |
50 | default |
51 | )] |
52 | pub snippet_copyright_text: Option<String>, |
53 | |
54 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#59-snippet-comment> |
55 | #[serde(rename = "comment" , skip_serializing_if = "Option::is_none" , default)] |
56 | pub snippet_comment: Option<String>, |
57 | |
58 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#510-snippet-name> |
59 | #[serde(rename = "name" , skip_serializing_if = "Option::is_none" , default)] |
60 | pub snippet_name: Option<String>, |
61 | |
62 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#511-snippet-attribution-text> |
63 | #[serde( |
64 | rename = "attributionText" , |
65 | skip_serializing_if = "Option::is_none" , |
66 | default |
67 | )] |
68 | pub snippet_attribution_text: Option<String>, |
69 | } |
70 | |
71 | /// <https://spdx.github.io/spdx-spec/5-snippet-information/#53-snippet-byte-range> |
72 | #[derive (Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] |
73 | #[serde(rename_all = "camelCase" )] |
74 | pub struct Range { |
75 | pub start_pointer: Pointer, |
76 | pub end_pointer: Pointer, |
77 | } |
78 | |
79 | impl Range { |
80 | pub fn new(start_pointer: Pointer, end_pointer: Pointer) -> Self { |
81 | Self { |
82 | start_pointer, |
83 | end_pointer, |
84 | } |
85 | } |
86 | } |
87 | |
88 | #[derive (Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] |
89 | #[serde(untagged)] |
90 | pub enum Pointer { |
91 | Byte { |
92 | reference: Option<String>, |
93 | offset: i32, |
94 | }, |
95 | Line { |
96 | reference: Option<String>, |
97 | #[serde(rename = "lineNumber" )] |
98 | line_number: i32, |
99 | }, |
100 | } |
101 | |
102 | impl Pointer { |
103 | /// Create a new [`Pointer::Byte`]. |
104 | pub fn new_byte(reference: Option<String>, offset: i32) -> Self { |
105 | Self::Byte { reference, offset } |
106 | } |
107 | |
108 | /// Create a new [`Pointer::Line`]. |
109 | pub fn new_line(reference: Option<String>, line_number: i32) -> Self { |
110 | Self::Line { |
111 | reference, |
112 | line_number, |
113 | } |
114 | } |
115 | } |
116 | |
117 | #[cfg (test)] |
118 | mod test { |
119 | use std::fs::read_to_string; |
120 | |
121 | use crate::models::SPDX; |
122 | |
123 | use super::*; |
124 | |
125 | #[test ] |
126 | fn snippet_spdx_identifier() { |
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.snippet_information[0].snippet_spdx_identifier, |
133 | "SPDXRef-Snippet" .to_string() |
134 | ); |
135 | } |
136 | #[test ] |
137 | fn snippet_from_file_spdx_identifier() { |
138 | let spdx: SPDX = serde_json::from_str( |
139 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
140 | ) |
141 | .unwrap(); |
142 | assert_eq!( |
143 | spdx.snippet_information[0].snippet_from_file_spdx_identifier, |
144 | "SPDXRef-DoapSource" .to_string() |
145 | ); |
146 | } |
147 | #[test ] |
148 | fn ranges() { |
149 | let spdx: SPDX = serde_json::from_str( |
150 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
151 | ) |
152 | .unwrap(); |
153 | assert_eq!( |
154 | spdx.snippet_information[0].ranges, |
155 | vec![ |
156 | Range { |
157 | end_pointer: Pointer::Line { |
158 | line_number: 23, |
159 | reference: Some("SPDXRef-DoapSource" .to_string()), |
160 | }, |
161 | start_pointer: Pointer::Line { |
162 | line_number: 5, |
163 | reference: Some("SPDXRef-DoapSource" .to_string()), |
164 | }, |
165 | }, |
166 | Range { |
167 | end_pointer: Pointer::Byte { |
168 | offset: 420, |
169 | reference: Some("SPDXRef-DoapSource" .to_string()), |
170 | }, |
171 | start_pointer: Pointer::Byte { |
172 | offset: 310, |
173 | reference: Some("SPDXRef-DoapSource" .to_string()), |
174 | }, |
175 | }, |
176 | ] |
177 | ); |
178 | } |
179 | #[test ] |
180 | fn snippet_concluded_license() { |
181 | let spdx: SPDX = serde_json::from_str( |
182 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
183 | ) |
184 | .unwrap(); |
185 | assert_eq!( |
186 | spdx.snippet_information[0] |
187 | .snippet_concluded_license |
188 | .as_ref() |
189 | .unwrap() |
190 | .clone(), |
191 | SpdxExpression::parse("GPL-2.0-only" ).unwrap() |
192 | ); |
193 | } |
194 | #[test ] |
195 | fn license_information_in_snippet() { |
196 | let spdx: SPDX = serde_json::from_str( |
197 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
198 | ) |
199 | .unwrap(); |
200 | assert_eq!( |
201 | spdx.snippet_information[0].license_information_in_snippet, |
202 | vec!["GPL-2.0-only" .to_string()] |
203 | ); |
204 | } |
205 | #[test ] |
206 | fn snippet_comments_on_license() { |
207 | let spdx: SPDX = serde_json::from_str( |
208 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
209 | ) |
210 | .unwrap(); |
211 | assert_eq!( |
212 | spdx.snippet_information[0].snippet_comments_on_license, |
213 | Some("The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz." .to_string()) |
214 | ); |
215 | } |
216 | #[test ] |
217 | fn snippet_copyright_text() { |
218 | let spdx: SPDX = serde_json::from_str( |
219 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
220 | ) |
221 | .unwrap(); |
222 | assert_eq!( |
223 | spdx.snippet_information[0] |
224 | .snippet_copyright_text |
225 | .as_ref() |
226 | .unwrap() |
227 | .clone(), |
228 | "Copyright 2008-2010 John Smith" .to_string() |
229 | ); |
230 | } |
231 | #[test ] |
232 | fn snippet_comment() { |
233 | let spdx: SPDX = serde_json::from_str( |
234 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
235 | ) |
236 | .unwrap(); |
237 | assert_eq!( |
238 | spdx.snippet_information[0].snippet_comment, |
239 | Some("This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0." .to_string()) |
240 | ); |
241 | } |
242 | #[test ] |
243 | fn snippet_name() { |
244 | let spdx: SPDX = serde_json::from_str( |
245 | &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json" ).unwrap(), |
246 | ) |
247 | .unwrap(); |
248 | assert_eq!( |
249 | spdx.snippet_information[0].snippet_name, |
250 | Some("from linux kernel" .to_string()) |
251 | ); |
252 | } |
253 | } |
254 | |