lix 0.18.0

Embeddable version control for apps and AI agents.
Documentation
use crate::storage::conformance::{StorageFactory, baseline, model_based, persistence};

pub type ConformanceResult = Result<(), String>;

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ConformanceReport {
    pub tests: Vec<ConformanceTest>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ConformanceTest {
    pub name: &'static str,
    pub status: ConformanceStatus,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConformanceStatus {
    Passed,
    Failed(String),
    Pending,
}

pub async fn run_storage_conformance<F>(factory: &F) -> ConformanceReport
where
    F: StorageFactory,
{
    let mut report = ConformanceReport::default();

    baseline::register(&mut report, factory).await;
    model_based::register(&mut report, factory).await;
    if !factory.config().ephemeral {
        persistence::register(&mut report, factory).await;
    }
    report
}

impl ConformanceReport {
    pub(crate) async fn run(
        &mut self,
        name: &'static str,
        test: impl Future<Output = ConformanceResult>,
    ) {
        let status = match test.await {
            Ok(()) => ConformanceStatus::Passed,
            Err(error) => ConformanceStatus::Failed(error),
        };
        self.tests.push(ConformanceTest { name, status });
    }

    pub fn failed(&self) -> impl Iterator<Item = &ConformanceTest> {
        self.tests
            .iter()
            .filter(|test| matches!(test.status, ConformanceStatus::Failed(_)))
    }

    pub fn pending(&self) -> impl Iterator<Item = &ConformanceTest> {
        self.tests
            .iter()
            .filter(|test| matches!(test.status, ConformanceStatus::Pending))
    }

    pub fn assert_no_failures(&self) {
        let problems = self
            .failed()
            .map(|test| match &test.status {
                ConformanceStatus::Failed(error) => format!("{}: {error}", test.name),
                _ => unreachable!("failed iterator only returns failed tests"),
            })
            .chain(
                self.pending()
                    .map(|test| format!("{}: pending capability conformance", test.name)),
            )
            .collect::<Vec<_>>();
        assert!(
            problems.is_empty(),
            "storage conformance problems:\n{}",
            problems.join("\n")
        );
    }
}