wasm-capability-contract 0.4.0

Generic, domain-agnostic capability pattern: CapabilityEngine/CapabilityRegistry/CapabilityDispatcher trait shapes + component/capability types. Trait definitions only -- see wasm-capability-core for this pattern's own default implementation, extracted from agent-runtime's ADR-001 (agent-runtime#31, ADR-011).
Documentation
//! Real-implementation tests for `CapabilityError`.

use wasm_capability_contract::CapabilityError;

/// @covers: CapabilityError
/// Each variant's `Display` message must name what actually happened —
/// a generic "invalid" with no context would leave a caller no way to
/// fix the real problem.
#[test]
fn test_capability_error_display_messages_name_the_failure() {
    assert_eq!(
        CapabilityError::UnsupportedContractVersion("swe:edge-handler@9.9.9".to_string())
            .to_string(),
        "unsupported contract version: swe:edge-handler@9.9.9"
    );
    assert_eq!(
        CapabilityError::InvalidManifest("component_bytes must not be empty".to_string())
            .to_string(),
        "invalid manifest: component_bytes must not be empty"
    );
    assert_eq!(
        CapabilityError::CapabilityUnavailable("clock not granted".to_string()).to_string(),
        "capability unavailable: clock not granted"
    );
}

/// @covers: CapabilityError
/// The engine-time variants added in `#3` must also name what happened
/// (`Trap`/`InvalidOutput`/`ResourceExhausted`) or carry a fixed,
/// still-informative message (`Cancelled`/`Timeout`, which have no
/// per-call detail to name).
#[test]
fn test_capability_error_display_messages_for_engine_time_variants() {
    assert_eq!(
        CapabilityError::Trap("division by zero".to_string()).to_string(),
        "component trap: division by zero"
    );
    assert_eq!(
        CapabilityError::InvalidOutput("export returned non-utf8 bytes".to_string()).to_string(),
        "invalid output: export returned non-utf8 bytes"
    );
    assert_eq!(
        CapabilityError::ResourceExhausted("max_memory_bytes exceeded".to_string()).to_string(),
        "resource exhausted: max_memory_bytes exceeded"
    );
    assert_eq!(
        CapabilityError::Cancelled.to_string(),
        "invocation cancelled"
    );
    assert_eq!(CapabilityError::Timeout.to_string(), "invocation timed out");
}

/// @covers: CapabilityError
/// Distinct variants with identical string payloads must never compare
/// equal — `Trap`/`InvalidOutput` are different failure classes even
/// when their message text happens to coincide.
#[test]
fn test_capability_error_eq_distinguishes_variants_with_same_payload() {
    let trap = CapabilityError::Trap("out of bounds".to_string());
    let invalid_output = CapabilityError::InvalidOutput("out of bounds".to_string());
    assert_ne!(trap, invalid_output);
}