use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum SessionStatus {
Queued,
Running,
Idle,
Rescheduling,
Paused,
Completed,
Failed,
Archived,
}
impl SessionStatus {
pub fn is_terminal(self) -> bool {
matches!(self, Self::Completed | Self::Failed | Self::Archived)
}
}
impl std::fmt::Display for SessionStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::Queued => "queued",
Self::Running => "running",
Self::Idle => "idle",
Self::Rescheduling => "rescheduling",
Self::Paused => "paused",
Self::Completed => "completed",
Self::Failed => "failed",
Self::Archived => "archived",
};
f.write_str(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_session_status_serializes_lowercase() {
let cases = [
(SessionStatus::Queued, "\"queued\""),
(SessionStatus::Running, "\"running\""),
(SessionStatus::Idle, "\"idle\""),
(SessionStatus::Rescheduling, "\"rescheduling\""),
(SessionStatus::Paused, "\"paused\""),
(SessionStatus::Completed, "\"completed\""),
(SessionStatus::Failed, "\"failed\""),
(SessionStatus::Archived, "\"archived\""),
];
for (status, expected) in cases {
let json = serde_json::to_string(&status).unwrap();
assert_eq!(json, expected, "serialization failed for {status:?}");
}
}
#[test]
fn test_session_status_deserializes_lowercase() {
let cases = [
("\"queued\"", SessionStatus::Queued),
("\"running\"", SessionStatus::Running),
("\"idle\"", SessionStatus::Idle),
("\"rescheduling\"", SessionStatus::Rescheduling),
("\"paused\"", SessionStatus::Paused),
("\"completed\"", SessionStatus::Completed),
("\"failed\"", SessionStatus::Failed),
("\"archived\"", SessionStatus::Archived),
];
for (json, expected) in cases {
let status: SessionStatus = serde_json::from_str(json).unwrap();
assert_eq!(status, expected, "deserialization failed for {json}");
}
}
#[test]
fn test_session_status_round_trip() {
let all_statuses = [
SessionStatus::Queued,
SessionStatus::Running,
SessionStatus::Idle,
SessionStatus::Rescheduling,
SessionStatus::Paused,
SessionStatus::Completed,
SessionStatus::Failed,
SessionStatus::Archived,
];
for status in all_statuses {
let json = serde_json::to_string(&status).unwrap();
let deserialized: SessionStatus = serde_json::from_str(&json).unwrap();
assert_eq!(status, deserialized, "round-trip failed for {status:?}");
}
}
#[test]
fn test_session_status_rejects_unknown() {
let result: Result<SessionStatus, _> = serde_json::from_str("\"unknown_status\"");
assert!(result.is_err());
}
#[test]
fn test_session_status_is_terminal() {
assert!(!SessionStatus::Queued.is_terminal());
assert!(!SessionStatus::Running.is_terminal());
assert!(!SessionStatus::Idle.is_terminal());
assert!(!SessionStatus::Rescheduling.is_terminal());
assert!(!SessionStatus::Paused.is_terminal());
assert!(SessionStatus::Completed.is_terminal());
assert!(SessionStatus::Failed.is_terminal());
assert!(SessionStatus::Archived.is_terminal());
}
#[test]
fn test_session_status_display() {
assert_eq!(SessionStatus::Queued.to_string(), "queued");
assert_eq!(SessionStatus::Running.to_string(), "running");
assert_eq!(SessionStatus::Idle.to_string(), "idle");
assert_eq!(SessionStatus::Rescheduling.to_string(), "rescheduling");
assert_eq!(SessionStatus::Paused.to_string(), "paused");
assert_eq!(SessionStatus::Completed.to_string(), "completed");
assert_eq!(SessionStatus::Failed.to_string(), "failed");
assert_eq!(SessionStatus::Archived.to_string(), "archived");
}
}