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