agentcarousel 0.2.3

Evaluate agents and skills with YAML fixtures, run cases (mock or live), and keep run rows in SQLite for reports and evidence export.
Documentation
use agentcarousel_core::{CaseStatus, Run};
use serde::Serialize;

#[derive(Serialize)]
#[serde(rename = "testsuite")]
struct TestSuite {
    #[serde(rename = "@name")]
    name: String,
    #[serde(rename = "@tests")]
    tests: usize,
    #[serde(rename = "@failures")]
    failures: usize,
    #[serde(rename = "@errors")]
    errors: usize,
    #[serde(rename = "testcase")]
    testcases: Vec<TestCase>,
}

#[derive(Serialize)]
struct TestCase {
    #[serde(rename = "@name")]
    name: String,
    #[serde(rename = "failure", skip_serializing_if = "Option::is_none")]
    failure: Option<Failure>,
    #[serde(rename = "error", skip_serializing_if = "Option::is_none")]
    error: Option<Failure>,
}

#[derive(Serialize)]
struct Failure {
    #[serde(rename = "$text")]
    message: String,
}

pub fn print_junit(run: &Run) {
    let mut failures = 0;
    let mut errors = 0;
    let mut testcases = Vec::new();

    for case in &run.cases {
        let mut failure = None;
        let mut error = None;
        match case.status {
            CaseStatus::Failed => {
                failures += 1;
                failure = Some(Failure {
                    message: case.error.clone().unwrap_or_else(|| "failed".to_string()),
                });
            }
            CaseStatus::Flaky => {
                failures += 1;
                failure = Some(Failure {
                    message: case.error.clone().unwrap_or_else(|| "flaky".to_string()),
                });
            }
            CaseStatus::TimedOut | CaseStatus::Error => {
                errors += 1;
                error = Some(Failure {
                    message: case.error.clone().unwrap_or_else(|| "error".to_string()),
                });
            }
            _ => {}
        }
        testcases.push(TestCase {
            name: case.case_id.0.clone(),
            failure,
            error,
        });
    }

    let suite = TestSuite {
        name: "agentcarousel".to_string(),
        tests: run.cases.len(),
        failures,
        errors,
        testcases,
    };

    let xml = quick_xml::se::to_string(&suite).unwrap_or_else(|_| "<testsuite />".to_string());
    println!("{xml}");
}