use anyhow::Context;
use serde::Serialize;
use xchecker_utils::canonicalization::emit_jcs;
use crate::types::{GateCondition, GateResult};
pub const GATE_JSON_SCHEMA_VERSION: &str = "gate-json.v1";
#[derive(Debug, Clone, Serialize)]
pub struct GateJsonOutput {
pub schema_version: String,
pub spec_id: String,
pub passed: bool,
pub conditions: Vec<GateCondition>,
pub failure_reasons: Vec<String>,
pub summary: String,
}
impl GateJsonOutput {
#[must_use]
pub fn new(result: &GateResult, spec_id: &str) -> Self {
Self {
schema_version: GATE_JSON_SCHEMA_VERSION.to_string(),
spec_id: spec_id.to_string(),
passed: result.passed,
conditions: result.conditions.clone(),
failure_reasons: result.failure_reasons.clone(),
summary: result.summary.clone(),
}
}
}
pub fn emit_gate_json(result: &GateResult, spec_id: &str) -> anyhow::Result<String> {
let output = GateJsonOutput::new(result, spec_id);
emit_jcs(&output).context("Failed to emit gate JSON")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{GateCondition, GateResult};
#[test]
fn test_emit_gate_json() {
let result = GateResult {
schema_version: "gate-json.v1".to_string(),
spec_id: "test-spec".to_string(),
passed: true,
summary: "Spec passed all checks".to_string(),
conditions: vec![GateCondition {
name: "Test condition".to_string(),
description: "A test condition".to_string(),
passed: true,
actual: Some("actual".to_string()),
expected: Some("expected".to_string()),
}],
failure_reasons: vec![],
};
let json = emit_gate_json(&result, "test-spec");
assert!(json.is_ok());
let json_str = json.unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
assert_eq!(parsed["schema_version"], "gate-json.v1");
assert_eq!(parsed["spec_id"], "test-spec");
assert_eq!(parsed["passed"], true);
assert_eq!(parsed["summary"], "Spec passed all checks");
assert_eq!(parsed["conditions"].as_array().unwrap().len(), 1);
assert!(parsed["failure_reasons"].as_array().unwrap().is_empty());
}
}