cranpose-services 0.1.163

Multiplatform system services for Cranpose (HTTP, URI, and OS integrations)
Documentation
use super::*;

struct WholeAssets;

impl BundledAssets for WholeAssets {
    fn read(&self, path: &str) -> Result<Vec<u8>, BundledAssetError> {
        match path {
            "big.bin" => Ok(vec![4u8; crate::content::DEFAULT_CHUNK_LEN + 9]),
            "small.txt" => Ok(b"hello".to_vec()),
            other => Err(BundledAssetError::NotFound(other.to_string())),
        }
    }
}

#[test]
fn a_length_bounded_reader_stops_at_the_asset_and_not_at_the_stream() {
    let asset_len = crate::content::DEFAULT_CHUNK_LEN + 5;
    let mut package = vec![7u8; asset_len];
    package.extend_from_slice(&[9u8; 64]);

    let mut reader = StreamingAssetReader::with_length(
        "model.bin",
        std::io::Cursor::new(package),
        asset_len as u64,
    );
    let mut read = Vec::new();
    while let Some(chunk) = reader.read_chunk().expect("chunks read") {
        read.extend_from_slice(&chunk);
    }

    assert_eq!(
        read.len(),
        asset_len,
        "the asset ends where its length says"
    );
    assert!(
        read.iter().all(|byte| *byte == 7),
        "no byte of what follows the asset in the package is handed out"
    );
}

#[test]
fn the_default_reader_streams_a_whole_asset_in_chunks() {
    let assets = WholeAssets;
    let mut reader = assets.open("big.bin").expect("the asset opens");
    let mut sizes = Vec::new();
    let mut total = 0usize;
    while let Some(chunk) = reader.read_chunk().expect("chunks read") {
        sizes.push(chunk.len());
        total += chunk.len();
    }
    assert_eq!(sizes, vec![crate::content::DEFAULT_CHUNK_LEN, 9]);
    assert_eq!(total, crate::content::DEFAULT_CHUNK_LEN + 9);
}

#[test]
fn a_missing_asset_fails_to_open() {
    assert!(matches!(
        WholeAssets.open("absent.bin").err(),
        Some(BundledAssetError::NotFound(_))
    ));
}

#[test]
fn a_backend_that_cannot_stat_reports_no_length() {
    assert_eq!(WholeAssets.len("small.txt"), None);
}

use std::{
    collections::BTreeMap,
    sync::atomic::{AtomicU64, Ordering},
};

#[test]
fn registration_round_trips() {
    let _guard = crate::registry::test_service_guard();
    struct Fake;
    impl BundledAssets for Fake {
        fn read(&self, path: &str) -> Result<Vec<u8>, BundledAssetError> {
            Ok(path.as_bytes().to_vec())
        }
    }
    set_platform_bundled_assets(Arc::new(Fake));
    assert_eq!(
        bundled_assets().unwrap().read("models/a").unwrap(),
        b"models/a"
    );
    clear_platform_bundled_assets();
    assert!(bundled_assets().is_none());
}

#[cfg(not(target_arch = "wasm32"))]
struct MapAssets(BTreeMap<String, Vec<u8>>);

#[cfg(not(target_arch = "wasm32"))]
impl BundledAssets for MapAssets {
    fn read(&self, path: &str) -> Result<Vec<u8>, BundledAssetError> {
        self.0
            .get(path)
            .cloned()
            .ok_or_else(|| BundledAssetError::NotFound(path.to_string()))
    }
}

#[cfg(not(target_arch = "wasm32"))]
fn test_directory() -> PathBuf {
    static NEXT: AtomicU64 = AtomicU64::new(1);
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../../target/test-output/bundled-assets")
        .join(format!(
            "{}-{}",
            std::process::id(),
            NEXT.fetch_add(1, Ordering::Relaxed)
        ))
}

#[cfg(not(target_arch = "wasm32"))]
#[test]
fn declarative_set_installs_and_detects_current_version() {
    let _guard = crate::registry::test_service_guard();
    let destination = test_directory();
    set_platform_bundled_assets(Arc::new(MapAssets(BTreeMap::from([
        ("models/a.bin".to_string(), vec![1, 2]),
        ("models/nested/b.bin".to_string(), vec![3]),
    ]))));
    let spec = BundledAssetInstallSpec::new("7", &destination)
        .source_root("models")
        .entry(BundledAssetEntry::new("a.bin"))
        .entry(BundledAssetEntry::mapped("nested/b.bin", "b.bin"));
    assert_eq!(
        install_bundled_asset_set(&spec).unwrap(),
        BundledAssetInstallOutcome::Installed
    );
    assert_eq!(std::fs::read(destination.join("a.bin")).unwrap(), [1, 2]);
    assert_eq!(std::fs::read(destination.join("b.bin")).unwrap(), [3]);
    assert_eq!(
        install_bundled_asset_set(&spec).unwrap(),
        BundledAssetInstallOutcome::Current
    );
    std::fs::remove_dir_all(destination).unwrap();
}

#[cfg(not(target_arch = "wasm32"))]
#[test]
fn declaration_rejects_parent_paths_and_handles_missing_host() {
    let _guard = crate::registry::test_service_guard();
    clear_platform_bundled_assets();
    let invalid = BundledAssetInstallSpec::new("1", test_directory())
        .entry(BundledAssetEntry::new("../outside"));
    assert!(matches!(
        install_bundled_asset_set(&invalid),
        Err(BundledAssetError::InvalidPath(_))
    ));
    let valid =
        BundledAssetInstallSpec::new("1", test_directory()).entry(BundledAssetEntry::new("inside"));
    assert_eq!(
        install_bundled_asset_set(&valid).unwrap(),
        BundledAssetInstallOutcome::Unavailable
    );
}