kcode-rust-bins 1.0.0

Author, validate, object-publish, and run small Rust binaries
Documentation
use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};

use kcode_rust_bins::{
    File, Lib, ObjectStore, ObjectStoreError, ObjectStoreResult, create, docs, open,
};

static TEST_COUNTER: AtomicU64 = AtomicU64::new(0);

#[derive(Default)]
struct MemoryObjects {
    objects: Mutex<BTreeMap<String, Vec<u8>>>,
}

impl ObjectStore for MemoryObjects {
    fn load(&self, object_id: &str) -> ObjectStoreResult<Vec<u8>> {
        self.objects
            .lock()
            .unwrap()
            .get(object_id)
            .cloned()
            .ok_or_else(|| ObjectStoreError::new("not found"))
    }

    fn save(&self, bytes: &[u8]) -> ObjectStoreResult<String> {
        let mut objects = self.objects.lock().unwrap();
        let id = format!("object-{}", objects.len());
        objects.insert(id.clone(), bytes.to_vec());
        Ok(id)
    }
}

struct TestRoot(PathBuf);

impl TestRoot {
    fn new(label: &str) -> Self {
        let counter = TEST_COUNTER.fetch_add(1, Ordering::Relaxed);
        let path = std::env::temp_dir().join(format!(
            "kcode-rust-bins-integration-{label}-{}-{counter}",
            std::process::id()
        ));
        fs::create_dir(&path).unwrap();
        Self(path)
    }

    fn path(&self) -> &Path {
        &self.0
    }
}

impl Drop for TestRoot {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.0);
    }
}

fn store() -> Arc<dyn ObjectStore> {
    Arc::new(MemoryObjects::default())
}

fn contents_mut<'a>(library: &'a mut Lib, path: &str) -> &'a mut String {
    &mut library
        .files
        .iter_mut()
        .find(|file| file.path == path)
        .unwrap()
        .contents
}

#[test]
fn create_open_and_docs_return_source_once_without_a_lockfile() {
    let root = TestRoot::new("open");
    let created = create(root.path(), "demo", store()).unwrap();
    assert_eq!(
        created
            .files
            .iter()
            .map(|file| file.path.as_str())
            .collect::<Vec<_>>(),
        ["Cargo.toml", "Documentation.md", "src/main.rs"]
    );
    assert_eq!(
        created
            .files
            .iter()
            .filter(|file| file.path == "Documentation.md")
            .count(),
        1
    );
    assert!(created.files.iter().all(|file| file.path != "Cargo.lock"));

    let opened = open(root.path(), "demo", store()).unwrap();
    assert_eq!(opened.files, created.files);
    assert_eq!(
        docs(root.path(), "demo").unwrap(),
        ("0.1.0".to_owned(), String::new())
    );
}

#[test]
fn complete_replacement_removes_omissions_and_refreshes_identity() {
    let root = TestRoot::new("replace");
    let mut library = create(root.path(), "demo", store()).unwrap();
    library.files.push(File {
        path: "tests/temporary.rs".to_owned(),
        contents: "#[test]\nfn temporary() {}\n".to_owned(),
    });
    library.write().unwrap();
    assert!(
        open(root.path(), "demo", store())
            .unwrap()
            .files
            .iter()
            .any(|file| file.path == "tests/temporary.rs")
    );

    library
        .files
        .retain(|file| file.path != "tests/temporary.rs");
    *contents_mut(&mut library, "Documentation.md") = "second write\n".to_owned();
    library.write().unwrap();
    let reopened = open(root.path(), "demo", store()).unwrap();
    assert!(
        reopened
            .files
            .iter()
            .all(|file| file.path != "tests/temporary.rs")
    );
    assert_eq!(docs(root.path(), "demo").unwrap().1, "second write\n");
}

#[test]
fn stale_writers_cannot_both_commit() {
    let root = TestRoot::new("stale");
    create(root.path(), "demo", store()).unwrap();
    let mut first = open(root.path(), "demo", store()).unwrap();
    let mut second = open(root.path(), "demo", store()).unwrap();
    *contents_mut(&mut first, "Documentation.md") = "first\n".to_owned();
    *contents_mut(&mut second, "Documentation.md") = "second\n".to_owned();
    first.write().unwrap();
    let error = second.write().unwrap_err();
    assert!(error.to_string().starts_with("stale_snapshot:"));
    assert_eq!(docs(root.path(), "demo").unwrap().1, "first\n");
}

#[test]
fn open_and_docs_migrate_a_legacy_flat_binary() {
    let root = TestRoot::new("migration");
    let repository = root.path().join("legacy");
    fs::create_dir(&repository).unwrap();
    fs::create_dir(repository.join("src")).unwrap();
    fs::write(
        repository.join("Cargo.toml"),
        "[package]\nname = \"legacy\"\nversion = \"2.3.4\"\nedition = \"2024\"\n",
    )
    .unwrap();
    fs::write(repository.join("Documentation.md"), "legacy API\n").unwrap();
    fs::write(repository.join("src/main.rs"), "fn main() {}\n").unwrap();
    fs::write(repository.join("Cargo.lock"), "version = 4\n").unwrap();

    let opened = open(root.path(), "legacy", store()).unwrap();
    assert!(opened.files.iter().all(|file| file.path != "Cargo.lock"));
    assert_eq!(
        docs(root.path(), "legacy").unwrap(),
        ("2.3.4".to_owned(), "legacy API\n".to_owned())
    );
    assert!(repository.join("HEAD").is_file());
    assert!(repository.join(".lock").is_file());
    assert!(repository.join("generations").is_dir());
}