zoi-rs 1.9.4

Universal Package Manager & Environment Setup Tool
Documentation
use std::fs;
use tempfile::tempdir;
use zoi::pkg::{plugin, sysroot};

#[test]
fn test_plugin_on_project_install_hook() {
    let tmp = tempdir().expect("Failed to create temp dir");
    let root = tmp.path().to_path_buf();
    sysroot::set_sysroot(root.clone());

    let pm = plugin::PluginManager::new().expect("Failed to create PluginManager");

    pm.lua
        .load(
            r#"
        zoi.on_project_install(function()
            return true
        end)
    "#,
        )
        .exec()
        .expect("Failed to load lua");

    let handled = pm.trigger_project_install_hook().expect("Hook failed");
    assert!(handled, "Hook should have returned true");
}

#[test]
fn test_plugin_fs_symlink_api() {
    let tmp = tempdir().expect("Failed to create temp dir");
    let root = tmp.path().to_path_buf();

    let target = root.join("target.txt");
    let link = root.join("link.txt");
    fs::write(&target, "hello").unwrap();

    let pm = plugin::PluginManager::new().unwrap();
    let script = format!(
        r#"return zoi.fs.symlink("{}", "{}", false)"#,
        target.to_str().unwrap().replace("\\", "/"),
        link.to_str().unwrap().replace("\\", "/")
    );

    let success: bool = pm.lua.load(&script).eval().unwrap();
    assert!(success, "Symlink API should return true");
    assert!(link.exists(), "Link should exist");
    assert_eq!(fs::read_to_string(link).unwrap(), "hello");
}

#[test]
fn test_plugin_archive_extract_api() {
    let tmp = tempdir().expect("Failed to create temp dir");
    let root = tmp.path().to_path_buf();

    let tar_path = root.join("test.tar.gz");
    let source_dir = root.join("src");
    fs::create_dir_all(source_dir.join("package")).unwrap();
    fs::write(source_dir.join("package/hello.txt"), "world").unwrap();

    {
        let file = fs::File::create(&tar_path).unwrap();
        let enc = flate2::write::GzEncoder::new(file, flate2::Compression::default());
        let mut tar = tar::Builder::new(enc);
        tar.append_dir_all("package", source_dir.join("package"))
            .unwrap();
        tar.finish().unwrap();
    }

    let pm = plugin::PluginManager::new().unwrap();
    let dest = root.join("dest");

    let script = format!(
        r#"return zoi.archive.extract("{}", "{}", 1)"#,
        tar_path.to_str().unwrap().replace("\\", "/"),
        dest.to_str().unwrap().replace("\\", "/")
    );

    let success: bool = pm.lua.load(&script).eval().unwrap();
    assert!(success, "Extract API should return true");
    assert!(
        dest.join("hello.txt").exists(),
        "hello.txt should be extracted to dest root due to strip=1"
    );
    assert_eq!(fs::read_to_string(dest.join("hello.txt")).unwrap(), "world");
}

#[test]
fn test_plugin_fs_copy_api() {
    let tmp = tempdir().expect("Failed to create temp dir");
    let root = tmp.path().to_path_buf();

    let src = root.join("src_dir");
    let dest = root.join("dest_dir");
    fs::create_dir_all(&src).unwrap();
    fs::write(src.join("file.txt"), "copy-content").unwrap();

    let pm = plugin::PluginManager::new().unwrap();
    let script = format!(
        r#"return zoi.fs.copy("{}", "{}")"#,
        src.to_str().unwrap().replace("\\", "/"),
        dest.to_str().unwrap().replace("\\", "/")
    );

    let success: bool = pm.lua.load(&script).eval().unwrap();
    assert!(success, "Copy API should return true");
    assert!(dest.join("file.txt").exists());
    assert_eq!(
        fs::read_to_string(dest.join("file.txt")).unwrap(),
        "copy-content"
    );
}

#[test]
fn test_plugin_sh_api() {
    let tmp = tempdir().expect("Failed to create temp dir");
    let root = tmp.path().to_path_buf();
    let out_file = root.join("sh_out.txt");

    let pm = plugin::PluginManager::new().unwrap();
    let script = format!(
        r#"return zoi.sh("echo 'sh-works' > {}")"#,
        out_file.to_str().unwrap().replace("\\", "/")
    );

    let exit_code: i32 = pm.lua.load(&script).eval().unwrap();
    assert_eq!(exit_code, 0, "zoi.sh should return 0 exit code");
    assert!(out_file.exists());
    assert_eq!(fs::read_to_string(out_file).unwrap().trim(), "sh-works");
}

#[test]
fn test_plugin_on_project_install_precedence() {
    let pm = plugin::PluginManager::new().expect("Failed to create PluginManager");

    pm.lua
        .load(
            r#"
        local run_count = 0
        zoi.on_project_install(function()
            run_count = run_count + 1
            return true
        end)
        zoi.on_project_install(function()
            run_count = run_count + 1
            return true
        end)
        
        function get_count() return run_count end
    "#,
        )
        .exec()
        .expect("Failed to load lua");

    let handled = pm.trigger_project_install_hook().expect("Hook failed");
    assert!(handled);

    let count: i32 = pm.lua.load("return get_count()").eval().unwrap();
    assert_eq!(
        count, 1,
        "Only the first hook that returns true should execute"
    );
}