use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::path::PathBuf;
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
pub enum UpdatePhase {
#[default]
#[serde(rename = "no-update")]
NoUpdate,
#[serde(rename = "prepare")]
Prepare,
#[serde(rename = "replace")]
Replace,
#[serde(rename = "cleanup")]
Cleanup,
}
impl Display for UpdatePhase {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UpdatePhase::NoUpdate => write!(f, "no-update"),
UpdatePhase::Prepare => write!(f, "prepare"),
UpdatePhase::Replace => write!(f, "replace"),
UpdatePhase::Cleanup => write!(f, "cleanup"),
}
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct UpdateState {
#[serde(rename = "app", default, skip_serializing_if = "Option::is_none")]
pub target_application: Option<PathBuf>,
#[serde(rename = "update", default, skip_serializing_if = "Option::is_none")]
pub temporary_application: Option<PathBuf>,
pub phase: UpdatePhase,
}
impl UpdateState {
pub fn for_phase(&self, phase: UpdatePhase) -> Self {
UpdateState {
target_application: self.target_application.clone(),
temporary_application: self.temporary_application.clone(),
phase,
}
}
}
impl Display for UpdateState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.phase)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serialize() {
assert_eq!(
serde_json::to_string(&UpdateState {
target_application: Some(PathBuf::from("/bin/app")),
temporary_application: Some(PathBuf::from("/tmp/app-update")),
phase: UpdatePhase::Replace
})
.unwrap(),
r#"{"app":"/bin/app","update":"/tmp/app-update","phase":"replace"}"#
);
assert_eq!(
serde_json::to_string(&UpdateState {
target_application: None,
temporary_application: Some(PathBuf::from("/tmp/app-update")),
phase: UpdatePhase::Cleanup
})
.unwrap(),
r#"{"update":"/tmp/app-update","phase":"cleanup"}"#
);
}
#[test]
fn test_deserialize() {
let update = UpdateState {
target_application: None,
temporary_application: Some(PathBuf::from("/tmp/app-update")),
phase: UpdatePhase::Cleanup,
};
let deserialized: UpdateState =
serde_json::from_str(r#"{"update":"/tmp/app-update","phase":"cleanup"}"#).unwrap();
assert_eq!(deserialized, update);
}
#[test]
fn test_to_string() {
assert_eq!(UpdatePhase::Prepare.to_string(), "prepare");
assert_eq!(UpdatePhase::Replace.to_string(), "replace");
assert_eq!(UpdatePhase::Cleanup.to_string(), "cleanup");
assert_eq!(UpdatePhase::NoUpdate.to_string(), "no-update");
}
#[test]
fn test_for_phase() {
let update = UpdateState {
target_application: Some(PathBuf::from("/bin/app")),
temporary_application: Some(PathBuf::from("/tmp/app-update")),
phase: UpdatePhase::Replace,
};
let new_update = update.for_phase(UpdatePhase::Cleanup);
assert_eq!(new_update.target_application, update.target_application);
assert_eq!(
new_update.temporary_application,
update.temporary_application
);
assert_eq!(
update.phase,
UpdatePhase::Replace,
"the old update entry should not be modified"
);
assert_eq!(
new_update.phase,
UpdatePhase::Cleanup,
"the new update entry should have the correct phase"
);
}
}