use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SolverStatus {
#[serde(rename = "NOT_SOLVING")]
NotSolving,
#[serde(rename = "SOLVING_ACTIVE")]
SolvingActive,
#[serde(rename = "TERMINATING_EARLY")]
TerminatingEarly,
#[serde(rename = "SOLVING_SCHEDULED")]
SolvingScheduled,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SolverStatusResponse {
#[serde(default)]
pub job_id: String,
pub solver_status: SolverStatus,
#[serde(default)]
pub score: String,
#[serde(default)]
pub feasible: bool,
#[serde(default)]
pub solving: bool,
}
impl SolverStatusResponse {
pub fn is_solving(&self) -> bool {
self.solving
|| self.solver_status == SolverStatus::SolvingScheduled
|| self.solver_status != SolverStatus::NotSolving
|| self.score.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn status(solving: bool, s: SolverStatus, score: &str) -> SolverStatusResponse {
SolverStatusResponse {
job_id: "j".into(),
solver_status: s,
score: score.into(),
feasible: true,
solving,
}
}
#[test]
fn done_only_when_idle_with_a_score() {
assert!(!status(false, SolverStatus::NotSolving, "0hard/0medium/0soft").is_solving());
}
#[test]
fn still_solving_in_every_other_case() {
assert!(status(true, SolverStatus::NotSolving, "0hard/0medium/0soft").is_solving());
assert!(status(false, SolverStatus::SolvingActive, "0hard/0medium/0soft").is_solving());
assert!(status(false, SolverStatus::SolvingScheduled, "0hard/0medium/0soft").is_solving());
assert!(status(false, SolverStatus::NotSolving, "").is_solving());
}
#[test]
fn deserializes_known_and_unknown_statuses() {
let known: SolverStatusResponse =
serde_json::from_str(r#"{"solverStatus":"SOLVING_ACTIVE"}"#).unwrap();
assert_eq!(known.solver_status, SolverStatus::SolvingActive);
let unknown: SolverStatusResponse =
serde_json::from_str(r#"{"solverStatus":"SOMETHING_NEW"}"#).unwrap();
assert_eq!(unknown.solver_status, SolverStatus::Unknown);
}
#[test]
fn tolerates_missing_optional_fields() {
let s: SolverStatusResponse =
serde_json::from_str(r#"{"solverStatus":"NOT_SOLVING"}"#).unwrap();
assert_eq!(s.job_id, "");
assert!(!s.feasible);
assert!(s.score.is_empty());
}
}