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 `CapabilityScope`.

use wasm_capability_contract::CapabilityScope;

fn round_trip(scope: &CapabilityScope) -> CapabilityScope {
    let json =
        serde_json::to_string(scope).unwrap_or_else(|e| panic!("serialize must succeed: {e}"));
    serde_json::from_str(&json).unwrap_or_else(|e| panic!("deserialize must succeed: {e}"))
}

/// @covers: CapabilityScope
/// A round trip through JSON must preserve every entry in `allowed`, in
/// order — not just that the field exists.
#[test]
fn test_capability_scope_json_round_trip_preserves_allowed_entries() {
    let original = CapabilityScope {
        allowed: vec![
            "api.example.com".to_string(),
            "other.example.com".to_string(),
        ],
    };
    assert_eq!(round_trip(&original), original);
}

/// @covers: CapabilityScope
/// An empty `allowed` list is a real, distinct value (nothing is
/// reachable) — it must round-trip as empty, not be conflated with a
/// missing field or a wildcard.
#[test]
fn test_capability_scope_json_round_trip_preserves_empty_allowed() {
    let original = CapabilityScope { allowed: vec![] };
    assert_eq!(round_trip(&original), original);
}

/// @covers: CapabilityScope
/// A literal `"*"` entry is preserved verbatim as plain data — this
/// contract has no opinion on whether it means "unrestricted" for any
/// given capability; that's a consumer-side interpretation.
#[test]
fn test_capability_scope_json_round_trip_preserves_wildcard_entry_as_plain_data() {
    let original = CapabilityScope {
        allowed: vec!["*".to_string()],
    };
    assert_eq!(round_trip(&original), original);
}