use anyhow::Result;
use serde::Serialize;
use super::Area;
use crate::exit::Code;
use crate::render;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub(super) enum Status {
Ok,
Problem,
Warning,
Note,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub(super) struct Row {
status: Status,
#[serde(skip_serializing_if = "Option::is_none")]
area: Option<Area>,
name: String,
detail: String,
}
impl Row {
pub(super) fn new(status: Status, area: Option<Area>, text: &str) -> Self {
let (name, detail) = match text.find(" ") {
Some(at) => (text[..at].trim(), text[at..].trim()),
None => ("", text.trim()),
};
Self {
status,
area,
name: name.to_owned(),
detail: detail.to_owned(),
}
}
}
#[derive(Serialize)]
struct Document<'a> {
healthy: bool,
problems: usize,
checks: &'a [Row],
}
pub(super) fn finish(rows: &[Row], problems: usize) -> Result<Code> {
render::json(&Document {
healthy: problems == 0,
problems,
checks: rows,
})?;
Ok(if problems == 0 { Code::Ok } else { Code::Usage })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_row_splits_its_label_from_the_detail() {
let row = Row::new(
Status::Ok,
Some(Area::Policy),
"policy /home/u/.moat/policy.yaml",
);
assert_eq!(
(row.name.as_str(), row.detail.as_str()),
("policy", "/home/u/.moat/policy.yaml")
);
let row = Row::new(
Status::Note,
None,
"Claude Code protection: hook + sandbox",
);
assert_eq!(row.name, "Claude Code");
let row = Row::new(Status::Warning, None, "healthy");
assert_eq!((row.name.as_str(), row.detail.as_str()), ("", "healthy"));
}
#[test]
fn the_document_names_each_status() {
let rows = [
Row::new(Status::Ok, Some(Area::Lock), "lock intact"),
Row::new(
Status::Problem,
Some(Area::Hook),
"Codex hook missing",
),
];
let value = serde_json::to_value(Document {
healthy: false,
problems: 1,
checks: &rows,
})
.unwrap();
assert_eq!(value["checks"][0]["status"], "ok");
assert_eq!(value["checks"][0]["area"], "lock");
assert_eq!(value["checks"][1]["status"], "problem");
assert_eq!(value["checks"][1]["detail"], "hook missing");
assert_eq!(value["healthy"], false);
}
}