kcode-rust-libs-v2 0.1.0

Manage, validate, and publish complete agent-authored Rust library snapshots
Documentation
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};

use kcode_rust_libs_v2::{Error, KcodeRustLibs, RustLibFile, RustLibPath};

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

struct TestDirectory(PathBuf);

impl TestDirectory {
    fn new(label: &str) -> Self {
        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_default()
            .as_nanos();
        let counter = TEMP_COUNTER.fetch_add(1, Ordering::Relaxed);
        let path = std::env::temp_dir().join(format!(
            "kcode-rust-libs-v2-test-{label}-{}-{timestamp}-{counter}",
            std::process::id()
        ));
        fs::create_dir(&path).unwrap();
        Self(path)
    }

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

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

fn manager(test: &TestDirectory) -> KcodeRustLibs {
    KcodeRustLibs::new(test.path().join("libraries"), "test-registry-token").unwrap()
}

#[test]
fn opens_one_complete_snapshot_without_a_second_documentation_representation() {
    let test = TestDirectory::new("snapshot");
    let manager = manager(&test);
    let mut opened = manager.create_rust_lib("calculator").unwrap();

    assert_eq!(opened.name(), "calculator");
    assert_eq!(opened.version(), "0.1.0");
    assert_eq!(
        opened
            .files()
            .iter()
            .map(|file| file.path.as_str())
            .collect::<Vec<_>>(),
        ["Cargo.toml", "Documentation.md", "src/lib.rs"]
    );
    assert_eq!(
        opened
            .files()
            .iter()
            .filter(|file| file.path.as_str() == "Documentation.md")
            .count(),
        1
    );

    opened
        .write(&[
            RustLibFile::new(
                RustLibPath::new("Documentation.md").unwrap(),
                "Call `answer()` to obtain the answer.\n",
            ),
            RustLibFile::new(
                RustLibPath::new("src/lib.rs").unwrap(),
                "pub fn answer() -> u8 { 42 }\n",
            ),
        ])
        .unwrap();
    assert_eq!(
        opened
            .files()
            .iter()
            .find(|file| file.path.as_str() == "Documentation.md")
            .unwrap()
            .contents,
        "Call `answer()` to obtain the answer.\n"
    );
}

#[test]
fn complete_file_writes_refresh_the_manifest_version_and_preserve_omitted_files() {
    let test = TestDirectory::new("write");
    let manager = manager(&test);
    let mut opened = manager.create_rust_lib("demo").unwrap();
    opened
        .write(&[
            RustLibFile::new(
                RustLibPath::new("Cargo.toml").unwrap(),
                "[package]\nname = \"demo\"\nversion = \"1.2.3\"\nedition = \"2024\"\n",
            ),
            RustLibFile::new(
                RustLibPath::new("tests/value.rs").unwrap(),
                "#[test]\nfn works() {}\n",
            ),
        ])
        .unwrap();
    assert_eq!(opened.version(), "1.2.3");
    assert!(
        opened
            .files()
            .iter()
            .any(|file| file.path.as_str() == "Documentation.md")
    );
    assert!(
        opened
            .files()
            .iter()
            .any(|file| file.path.as_str() == "tests/value.rs")
    );
}

#[test]
fn rejects_invalid_metadata_before_replacing_an_earlier_file() {
    let test = TestDirectory::new("metadata");
    let manager = manager(&test);
    let mut opened = manager.create_rust_lib("demo").unwrap();
    let result = opened.write(&[
        RustLibFile::new(RustLibPath::new("src/lib.rs").unwrap(), "changed\n"),
        RustLibFile::new(
            RustLibPath::new("Cargo.toml").unwrap(),
            "[package]\nname = \"demo\"\nversion = \"1.2.3-beta\"\n",
        ),
    ]);
    assert!(matches!(result, Err(Error::InvalidVersion(_))));
    assert_eq!(
        fs::read_to_string(test.path().join("libraries/demo/src/lib.rs")).unwrap(),
        ""
    );
}

#[test]
fn rejects_empty_tokens_before_creating_the_persistent_root() {
    for token in ["", " \n\t"] {
        let test = TestDirectory::new("token");
        let root = test.path().join("libraries");
        assert!(matches!(
            KcodeRustLibs::new(&root, token),
            Err(Error::InvalidRegistryToken)
        ));
        assert!(!root.exists());
    }
}

#[test]
fn manager_debug_output_redacts_the_registry_token() {
    let test = TestDirectory::new("debug");
    let manager = KcodeRustLibs::new(test.path().join("libraries"), "debug-secret").unwrap();
    let debug = format!("{manager:?}");
    assert!(!debug.contains("debug-secret"));
    assert!(debug.contains("[REDACTED]"));
}

#[test]
fn rejects_bad_names_and_duplicate_write_paths() {
    let test = TestDirectory::new("validation");
    let manager = manager(&test);
    for name in ["", "../outside", "with/slash", "two words", "_leading"] {
        assert!(matches!(
            manager.create_rust_lib(name),
            Err(Error::InvalidRustLibName(_))
        ));
    }

    let mut opened = manager.create_rust_lib("demo").unwrap();
    let path = RustLibPath::new("src/lib.rs").unwrap();
    assert!(matches!(
        opened.write(&[
            RustLibFile::new(path.clone(), "first"),
            RustLibFile::new(path, "second"),
        ]),
        Err(Error::DuplicateWritePath(_))
    ));
}

#[cfg(unix)]
#[test]
fn rejects_symlinks_during_open_and_write() {
    use std::os::unix::fs::symlink;

    let test = TestDirectory::new("symlink");
    let manager = manager(&test);
    let mut opened = manager.create_rust_lib("demo").unwrap();
    let outside = test.path().join("outside");
    fs::create_dir(&outside).unwrap();
    symlink(&outside, test.path().join("libraries/demo/link")).unwrap();
    assert!(matches!(
        opened.write(&[RustLibFile::new(
            RustLibPath::new("link/file.rs").unwrap(),
            "outside"
        )]),
        Err(Error::SymlinkNotAllowed(_))
    ));
    assert!(!outside.join("file.rs").exists());
    drop(opened);
    assert!(matches!(
        manager.open_rust_lib("demo"),
        Err(Error::SymlinkNotAllowed(_))
    ));
}