axhvc 0.4.11

AxVisor HyperCall definitions for guest-hypervisor communication
Documentation
use std::{fs, path::Path};

use axhvc::{HyperCallCode, HyperCallError, HyperCallResult, InvalidHyperCallCode};

#[test]
fn crate_uses_typed_errors_without_errno_contracts() {
    let crate_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
    let manifest = fs::read_to_string(crate_dir.join("Cargo.toml")).unwrap();
    let sources = fs::read_to_string(crate_dir.join("src/lib.rs")).unwrap()
        + &fs::read_to_string(crate_dir.join("src/error.rs")).unwrap();

    let errno_package = ["ax", "-errno"].concat();
    let errno_module = ["ax", "_errno"].concat();
    assert!(!manifest.contains(&errno_package));
    assert!(!sources.contains(&errno_module));
    assert!(manifest.contains("thiserror = { workspace = true }"));

    fn assert_error_contract<T: core::error::Error + Clone + Eq>() {}
    fn assert_result_alias(_: HyperCallResult<usize>) {}
    assert_error_contract::<InvalidHyperCallCode>();
    assert_error_contract::<HyperCallError>();
    assert_result_alias(Ok(0));
}

#[test]
fn errors_preserve_code_resource_and_guest_address_context() {
    let invalid: HyperCallError = InvalidHyperCallCode(0xff).into();
    assert!(matches!(invalid, HyperCallError::InvalidCode(_)));
    assert!(invalid.to_string().contains("0xff"));

    let conflict = HyperCallError::ResourceConflict {
        code: HyperCallCode::HIVCPublishChannel,
        resource: "IVC channel 7".into(),
        detail: "already published".into(),
    };
    assert!(conflict.to_string().contains("IVC channel 7"));

    let access = HyperCallError::GuestMemoryAccess {
        code: HyperCallCode::HIVCSubscribChannel,
        operation: "write subscription result",
        address: 0x4000,
        detail: "unmapped guest page".into(),
    };
    assert!(access.to_string().contains("0x4000"));
}

#[test]
fn execution_error_categories_remain_matchable() {
    let code = HyperCallCode::HIVCPublishChannel;
    let errors = [
        HyperCallError::Unsupported {
            code,
            detail: "disabled by host policy".into(),
        },
        HyperCallError::InvalidParameter {
            code,
            parameter: "shm_size_ptr",
            detail: "address is not aligned".into(),
        },
        HyperCallError::InvalidState {
            code,
            detail: "channel was unpublished".into(),
        },
        HyperCallError::ResourceNotFound {
            code,
            resource: "IVC channel 7".into(),
            detail: "publisher does not own the key".into(),
        },
        HyperCallError::OutOfMemory {
            code,
            operation: "allocate shared frame",
        },
        HyperCallError::Internal {
            code,
            operation: "map shared frame",
            detail: "stage-2 mapping failed".into(),
        },
    ];

    assert!(matches!(errors[0], HyperCallError::Unsupported { .. }));
    assert!(matches!(errors[1], HyperCallError::InvalidParameter { .. }));
    assert!(matches!(errors[2], HyperCallError::InvalidState { .. }));
    assert!(matches!(errors[3], HyperCallError::ResourceNotFound { .. }));
    assert!(matches!(errors[4], HyperCallError::OutOfMemory { .. }));
    assert!(matches!(errors[5], HyperCallError::Internal { .. }));
    for error in errors {
        assert!(error.to_string().contains("HIVCPublishChannel"));
    }
}