use serde_json::Value;
#[derive(Debug, Default)]
pub(crate) struct TerminalGuard {
finished: bool,
}
impl TerminalGuard {
pub fn new() -> Self {
Self { finished: false }
}
pub fn is_finished(&self) -> bool {
self.finished
}
pub fn mark_finished(&mut self) {
self.finished = true;
}
}
#[derive(Debug)]
pub(crate) enum ResumedOutcome<'a> {
Error { message: &'a str },
Denied,
Success,
}
pub(crate) fn classify_resumed_result(result: &Value) -> ResumedOutcome<'_> {
if let Some(error_msg) = result.get("error").and_then(Value::as_str) {
ResumedOutcome::Error { message: error_msg }
} else if result.get("approved") == Some(&serde_json::json!(false)) {
ResumedOutcome::Denied
} else {
ResumedOutcome::Success
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn terminal_guard_starts_unfinished() {
let guard = TerminalGuard::new();
assert!(!guard.is_finished());
}
#[test]
fn terminal_guard_default_starts_unfinished() {
let guard = TerminalGuard::default();
assert!(!guard.is_finished());
}
#[test]
fn terminal_guard_mark_finished_sets_flag() {
let mut guard = TerminalGuard::new();
guard.mark_finished();
assert!(guard.is_finished());
}
#[test]
fn terminal_guard_mark_finished_is_idempotent() {
let mut guard = TerminalGuard::new();
guard.mark_finished();
guard.mark_finished();
assert!(guard.is_finished());
}
#[test]
fn resumed_error_with_message() {
let result = json!({"error": "something went wrong"});
match classify_resumed_result(&result) {
ResumedOutcome::Error { message } => {
assert_eq!(message, "something went wrong");
}
other => panic!("expected Error, got: {other:?}"),
}
}
#[test]
fn resumed_error_non_string_treated_as_success() {
let result = json!({"error": 42});
assert!(matches!(
classify_resumed_result(&result),
ResumedOutcome::Success
));
}
#[test]
fn resumed_denied() {
let result = json!({"approved": false});
assert!(matches!(
classify_resumed_result(&result),
ResumedOutcome::Denied
));
}
#[test]
fn resumed_approved_true_is_success() {
let result = json!({"approved": true});
assert!(matches!(
classify_resumed_result(&result),
ResumedOutcome::Success
));
}
#[test]
fn resumed_no_special_fields_is_success() {
let result = json!({"data": "hello"});
assert!(matches!(
classify_resumed_result(&result),
ResumedOutcome::Success
));
}
#[test]
fn resumed_empty_object_is_success() {
let result = json!({});
assert!(matches!(
classify_resumed_result(&result),
ResumedOutcome::Success
));
}
#[test]
fn resumed_error_takes_precedence_over_denied() {
let result = json!({"error": "fail", "approved": false});
assert!(matches!(
classify_resumed_result(&result),
ResumedOutcome::Error { .. }
));
}
}