serde_sarif/
sarif.rs

1#![allow(clippy::derive_partial_eq_without_eq)]
2
3use strum_macros::Display;
4use strum_macros::EnumString;
5use thiserror::Error;
6
7include!(concat!(env!("OUT_DIR"), "/sarif.rs"));
8
9#[doc = "The SARIF format version of this log file."]
10#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
11pub enum Version {
12  #[strum(serialize = "2.1.0")]
13  #[serde(rename = "2.1.0")]
14  V2_1_0,
15}
16
17// todo: should be generated / synced with schema.json
18pub static SCHEMA_URL: &str =
19  "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json";
20
21#[doc = "The role or roles played by the artifact in the analysis."]
22#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
23#[serde(rename_all = "camelCase")]
24#[strum(serialize_all = "camelCase")]
25pub enum ArtifactRoles {
26  AnalysisTarget,
27  Attachment,
28  ResponseFile,
29  ResultFile,
30  StandardStream,
31  TracedFile,
32  Unmodified,
33  Modified,
34  Added,
35  Deleted,
36  Renamed,
37  Uncontrolled,
38  Driver,
39  Extension,
40  Translation,
41  Taxonomy,
42  Policy,
43  ReferencedOnCommandLine,
44  MemoryContents,
45  Directory,
46  UserSpecifiedConfiguration,
47  ToolSpecifiedConfiguration,
48  DebugOutputFile,
49}
50
51#[doc = "The SARIF format version of this external properties object."]
52#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
53pub enum ExternalPropertiesVersion {
54  #[strum(serialize = "2.1.0")]
55  #[serde(rename = "2.1.0")]
56  V2_1_0,
57}
58
59#[doc = "A value specifying the severity level of the result."]
60#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
61#[serde(rename_all = "camelCase")]
62#[strum(serialize_all = "camelCase")]
63pub enum NotificationLevel {
64  None,
65  Note,
66  Warning,
67  Error,
68}
69
70#[doc = "Specifies the failure level for the report."]
71#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
72#[serde(rename_all = "camelCase")]
73#[strum(serialize_all = "camelCase")]
74pub enum ReportingConfigurationLevel {
75  None,
76  Note,
77  Warning,
78  Error,
79}
80
81#[doc = "A value that categorizes results by evaluation state."]
82#[derive(
83  Clone, Display, Debug, Serialize, Deserialize, EnumString, PartialEq,
84)]
85#[serde(rename_all = "camelCase")]
86#[strum(serialize_all = "camelCase")]
87pub enum ResultKind {
88  NotApplicable,
89  Pass,
90  Fail,
91  Review,
92  Open,
93  Informational,
94}
95
96#[doc = "A value specifying the severity level of the result."]
97#[derive(
98  Clone, Copy, Display, Debug, Serialize, Deserialize, EnumString, PartialEq,
99)]
100#[serde(rename_all = "camelCase")]
101#[strum(serialize_all = "camelCase")]
102pub enum ResultLevel {
103  None,
104  Note,
105  Warning,
106  Error,
107}
108
109#[doc = "The state of a result relative to a baseline of a previous run."]
110#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
111#[serde(rename_all = "camelCase")]
112#[strum(serialize_all = "camelCase")]
113pub enum ResultBaselineState {
114  New,
115  Unchanged,
116  Updated,
117  Absent,
118}
119
120#[doc = "Specifies the unit in which the tool measures columns."]
121#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
122#[serde(rename_all = "camelCase")]
123#[strum(serialize_all = "camelCase")]
124pub enum ResultColumnKind {
125  Utf16CodeUnits,
126  UnicodeCodePoints,
127}
128
129#[doc = "A string that indicates where the suppression is persisted."]
130#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
131#[serde(rename_all = "camelCase")]
132#[strum(serialize_all = "camelCase")]
133pub enum SupressionKind {
134  InSource,
135  External,
136}
137
138#[doc = "A string that indicates the review status of the suppression."]
139#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
140#[serde(rename_all = "camelCase")]
141#[strum(serialize_all = "camelCase")]
142pub enum SupressionStatus {
143  Accepted,
144  UnderReview,
145}
146
147#[doc = "Specifies the importance of this location in understanding the code flow in which it occurs. The order from most to least important is \"essential\", \"important\", \"unimportant\". Default: \"important\"."]
148#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
149#[serde(rename_all = "camelCase")]
150#[strum(serialize_all = "camelCase")]
151pub enum ThreadFlowLocationImportance {
152  Important,
153  Essential,
154}
155
156#[doc = "The kinds of data contained in this object."]
157#[derive(Display, Debug, Serialize, Deserialize, EnumString)]
158#[serde(rename_all = "camelCase")]
159#[strum(serialize_all = "camelCase")]
160pub enum ToolComponentContents {
161  LocalizedData,
162  NonLocalizedData,
163}
164
165#[derive(Error, Debug)]
166pub enum BuilderError {
167  #[error("uninitialized field: {0}")]
168  UninitializedField(&'static str),
169}
170
171// Note that due to the blanket implementation in core, TryFrom<AsRef<String>>
172// results in a compiler error.
173// https://github.com/rust-lang/rust/issues/50133
174impl From<&String> for MultiformatMessageString {
175  fn from(message: &String) -> Self {
176    MultiformatMessageString::builder()
177      .text(message.clone())
178      .build()
179  }
180}
181
182impl From<&String> for Message {
183  fn from(message: &String) -> Self {
184    Message::builder().text(message.clone()).build()
185  }
186}
187
188impl From<&str> for Message {
189  fn from(message: &str) -> Self {
190    Message::builder().text(message).build()
191  }
192}
193
194impl From<ToolComponent> for Tool {
195  fn from(tool_component: ToolComponent) -> Self {
196    Tool::builder().driver(tool_component).build()
197  }
198}
199
200#[cfg(test)]
201mod tests {
202  use std::str::FromStr;
203
204  use super::*;
205  macro_rules! map {
206    ($( $key: expr => $val: expr ),*) => {{
207         let mut map = ::std::collections::BTreeMap::new();
208         $( map.insert($key, serde_json::json!($val)); )*
209         map
210    }}
211}
212
213  #[test]
214  fn test_serialize_property_bag_empty() {
215    let property_bag = PropertyBag::builder().build();
216    let json = serde_json::to_string_pretty(&property_bag).unwrap();
217    let json_expected = r#"{}"#;
218    assert_eq!(json, json_expected);
219  }
220
221  #[test]
222  fn test_serialize_property_bag_additional_properties() {
223    let property_bag = PropertyBag::builder()
224      .additional_properties(map!["key1".to_string() => "value1"])
225      .build();
226    let json = serde_json::to_string_pretty(&property_bag).unwrap();
227    let json_expected = r#"{
228  "key1": "value1"
229}"#;
230    assert_eq!(json, json_expected);
231  }
232
233  #[test]
234  fn test_deserialize_property_bag_empty() {
235    let json = r#"{}"#;
236    let property_bag: PropertyBag = serde_json::from_str(json).unwrap();
237    let property_bag_expected = PropertyBag::builder().build();
238    assert_eq!(property_bag, property_bag_expected);
239  }
240
241  #[test]
242  fn test_deserialize_property_bag_additional_properties() {
243    let json = r#"{
244      "key1": "value1"
245    }"#;
246    let property_bag: PropertyBag = serde_json::from_str(json).unwrap();
247    let property_bag_expected = PropertyBag::builder()
248      .additional_properties(map!["key1".to_string() => "value1"])
249      .build();
250    assert_eq!(property_bag, property_bag_expected);
251  }
252
253  #[test]
254  fn test_serialize_resultkind() {
255    assert_eq!(
256      serde_json::to_string(&ResultKind::Fail).unwrap(),
257      "\"fail\""
258    );
259  }
260
261  #[test]
262  fn test_parse_utf16codeunits() {
263    let v = ResultColumnKind::from_str("utf16CodeUnits").unwrap();
264    assert!(matches!(v, ResultColumnKind::Utf16CodeUnits));
265  }
266}