haematite-cli 0.21.8

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use super::failure::Failure;
use crate::serve::receipt_fragments::{Assembler, minimum_cap};
use haematite::{ApiError, BatchFailure, DatabaseError, LeafLogError, ObserverError};
use std::error::Error;

type TestResult = Result<(), Box<dyn Error>>;

fn batch_error() -> Result<DatabaseError, Box<dyn Error>> {
    let failure = BatchFailure::new(crate::serve::receipt_wire_tests::fixture()?)?;
    Ok(DatabaseError::BatchFailed(Box::new(failure)))
}

#[test]
fn original_typed_wrappers_retain_complete_receipt_and_full_cause() -> TestResult {
    let failures = [
        Failure::database(batch_error()?),
        Failure::api(ApiError::Storage(batch_error()?)),
        Failure::leaf_log(LeafLogError::Storage(batch_error()?)),
        Failure::observer(ObserverError::Config(batch_error()?)),
        Failure::observer(ObserverError::Api(ApiError::Storage(batch_error()?))),
    ];
    let cap = u32::try_from(minimum_cap()?)?;
    for failure in failures {
        let source = Error::source(&failure).ok_or("failure has no source")?;
        let original = source.to_string();
        let cloned = failure.clone();
        let cloned_source = Error::source(&cloned).ok_or("clone has no source")?;
        assert_eq!(cloned_source.to_string(), original);
        let encoded = failure.seal()?.ok_or("typed failure sealed no receipt")?;
        let mut assembler = Assembler::new("typed", cap)?;
        let mut complete = None;
        for frame in encoded.frames("typed", cap)? {
            if let Some(receipt) = assembler.accept(&frame)? {
                assert!(complete.is_none());
                complete = Some(receipt);
            }
        }
        let complete = complete.ok_or("assembler never completed the receipt")?;
        assert_eq!(complete.bytes(), encoded.bytes());
        let receipt = complete.receipt().ok_or("packet has no receipt")?;
        assert_eq!(receipt.outcomes.len(), 5);
        let refusal = complete.refusal().ok_or("packet has no refusal")?;
        assert_eq!(refusal.message, failure.message);
        let cause = refusal.cause.as_ref().ok_or("refusal carries no cause")?;
        assert_eq!(cause.message, original);
        assert!(cause.database.is_some());
        let kept_source = Error::source(&failure).ok_or("failure lost its source")?;
        assert_eq!(kept_source.to_string(), original);
    }
    Ok(())
}

#[test]
fn diagnostic_has_no_fabricated_receipt_or_original_database_cause() -> TestResult {
    let failure = Failure::new("invalid_document", "invalid JSON before effects");
    assert!(failure.seal()?.is_none());
    assert!(Error::source(&failure).is_none());
    Ok(())
}

#[test]
fn actual_barrier_kind_and_complete_received_message_remain_owned() -> TestResult {
    let error = haematite::BranchCommitError::Barrier("original received barrier".repeat(4096));
    let message = error.to_string();
    let failure = Failure::branch_commit(error);
    let source = Error::source(&failure).ok_or("barrier has no source")?;
    assert_eq!(source.to_string(), message);
    let cap = u32::try_from(minimum_cap()?)?;
    let encoded = failure.seal()?.ok_or("barrier failure sealed no packet")?;
    let frames = encoded.frames("barrier", cap)?;
    assert!(frames.len() > 2);
    let mut assembler = Assembler::new("barrier", cap)?;
    let mut complete = None;
    for frame in frames {
        if let Some(receipt) = assembler.accept(&frame)? {
            complete = Some(receipt);
        }
    }
    let complete = complete.ok_or("assembler never completed the packet")?;
    assert!(complete.receipt().is_none());
    let refusal = complete.refusal().ok_or("packet has no refusal")?;
    let cause = refusal.cause.as_ref().ok_or("refusal carries no cause")?;
    assert_eq!(cause.message, message);
    Ok(())
}