use serde::{Deserialize, Serialize};
pub const COLD_START: &str = "cold_start";
pub const INGESTION_DROPS: &str = "ingestion_drops";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Warning {
pub kind: String,
pub message: String,
}
impl Warning {
#[must_use]
pub fn new(kind: impl Into<String>, message: impl Into<String>) -> Self {
Self {
kind: kind.into(),
message: message.into(),
}
}
#[must_use]
pub fn from_untrusted(kind: &str, message: &str) -> Self {
Self {
kind: crate::report::sarif::strip_bidi_and_invisible(kind).into_owned(),
message: crate::report::sarif::strip_bidi_and_invisible(message).into_owned(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn warning_serde_roundtrip() {
let w = Warning::new(COLD_START, "daemon has not yet processed any events");
let json = serde_json::to_string(&w).expect("serialize");
let parsed: Warning = serde_json::from_str(&json).expect("deserialize");
assert_eq!(parsed, w);
}
#[test]
fn warning_new_accepts_str_and_string() {
let from_str = Warning::new("k", "m");
let from_string = Warning::new(String::from("k"), String::from("m"));
assert_eq!(from_str, from_string);
}
#[test]
fn warning_from_untrusted_strips_bidi_and_invisible() {
let w = Warning::from_untrusted(
"alert\u{202E}_kind",
"msg with\u{202E}override and\u{200B}zwsp",
);
assert!(!w.kind.contains('\u{202E}'));
assert!(!w.message.contains('\u{202E}'));
assert!(!w.message.contains('\u{200B}'));
}
#[test]
fn warning_kind_constants_match_documented_values() {
assert_eq!(COLD_START, "cold_start");
assert_eq!(INGESTION_DROPS, "ingestion_drops");
}
}