callisto_model/
severity.rs1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)]
11#[serde(rename_all = "lowercase")]
12pub enum Severity {
13 None,
14 Patch,
15 Minor,
16 Major,
17}
18
19impl Severity {
20 pub const ALL: [Severity; 4] = [Severity::None, Severity::Patch, Severity::Minor, Severity::Major];
23}
24
25impl std::str::FromStr for Severity {
28 type Err = SeverityParseError;
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 match s.trim().to_ascii_lowercase().as_str() {
31 "major" => Ok(Severity::Major),
32 "minor" => Ok(Severity::Minor),
33 "patch" => Ok(Severity::Patch),
34 "none" => Ok(Severity::None),
35 _ => Err(SeverityParseError { found: s.to_string() }),
36 }
37 }
38}
39
40impl std::fmt::Display for Severity {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 f.write_str(match self {
43 Severity::Major => "major",
44 Severity::Minor => "minor",
45 Severity::Patch => "patch",
46 Severity::None => "none",
47 })
48 }
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
53#[error("invalid severity {found:?}: expected one of \"major\", \"minor\", \"patch\", \"none\" (case-insensitive)")]
54pub struct SeverityParseError {
55 pub found: String,
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use std::str::FromStr;
62
63 #[test]
64 fn parses_lowercase_variants() {
65 assert_eq!(Severity::from_str("major").unwrap(), Severity::Major);
66 assert_eq!(Severity::from_str("minor").unwrap(), Severity::Minor);
67 assert_eq!(Severity::from_str("patch").unwrap(), Severity::Patch);
68 assert_eq!(Severity::from_str("none").unwrap(), Severity::None);
69 }
70
71 #[test]
72 fn parses_case_insensitively() {
73 assert_eq!(Severity::from_str("MAJOR").unwrap(), Severity::Major);
74 assert_eq!(Severity::from_str("Minor").unwrap(), Severity::Minor);
75 }
76
77 #[test]
78 fn rejects_unknown_token() {
79 let err = Severity::from_str("critical").unwrap_err();
80 assert_eq!(err.found, "critical");
81 }
82
83 #[test]
84 fn displays_lowercase_regardless_of_input_case() {
85 assert_eq!(Severity::Major.to_string(), "major");
86 assert_eq!(Severity::None.to_string(), "none");
87 }
88
89 #[test]
90 fn orders_none_patch_minor_major_ascending() {
91 assert!(Severity::None < Severity::Patch);
92 assert!(Severity::Patch < Severity::Minor);
93 assert!(Severity::Minor < Severity::Major);
94 }
95
96 #[test]
97 fn max_of_mixed_severities_picks_highest() {
98 let severities = [Severity::Patch, Severity::None, Severity::Major, Severity::Minor];
99 assert_eq!(severities.iter().copied().max().unwrap(), Severity::Major);
100 }
101}