From ba7793315709f26b0de3dc3b116fe5477a43b61b Mon Sep 17 00:00:00 2001 From: Khaled Alam <188656344+k5602@users.noreply.github.com> Date: Fri, 27 Mar 2026 05:52:43 +0200 Subject: [PATCH] feat(rs_port): Improve custom install path handling and add tests Add tests to verify the behavior of `get_search_config` when `METACALL_INSTALL_PATH` is set. Ensure that an empty `METACALL_INSTALL_PATH` is ignored, and the default platform paths are used. Refine the handling of custom paths to explicitly check if the provided path is non-empty. Update dependency versions in `Cargo.toml` files to reflect the latest changes. --- source/ports/rs_port/Cargo.toml | 2 +- source/ports/rs_port/sys/Cargo.toml | 2 +- source/ports/rs_port/sys/src/lib.rs | 88 ++++++++++++++++++++++++----- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/source/ports/rs_port/Cargo.toml b/source/ports/rs_port/Cargo.toml index 825130374b..b188d3d443 100644 --- a/source/ports/rs_port/Cargo.toml +++ b/source/ports/rs_port/Cargo.toml @@ -19,7 +19,7 @@ path = "src/lib.rs" metacall-inline = { version = "0.2.0", path = "./inline" } [build-dependencies] -metacall-sys = { version = "0.1.4", path = "./sys" } +metacall-sys = { version = "0.1.5", path = "./sys" } bindgen = "0.72.1" [workspace] diff --git a/source/ports/rs_port/sys/Cargo.toml b/source/ports/rs_port/sys/Cargo.toml index 957e1b2cf0..bb7f58d3d5 100644 --- a/source/ports/rs_port/sys/Cargo.toml +++ b/source/ports/rs_port/sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "metacall-sys" -version = "0.1.4" +version = "0.1.5" repository = "https://github.com/metacall/core/tree/develop/source/ports/rs_port/sys" keywords = ["ffi", "bindings", "metacall"] edition = "2021" diff --git a/source/ports/rs_port/sys/src/lib.rs b/source/ports/rs_port/sys/src/lib.rs index 4c77f3fc34..f99092729f 100644 --- a/source/ports/rs_port/sys/src/lib.rs +++ b/source/ports/rs_port/sys/src/lib.rs @@ -10,6 +10,7 @@ use std::{ // Provide helpful error messages when things aren't found /// Represents the install paths for a platform +#[derive(Debug, PartialEq, Eq)] struct InstallPath { paths: Vec, names: Vec<&'static str>, @@ -94,20 +95,22 @@ fn platform_install_paths() -> Result> { /// Get search paths, checking for custom installation path first fn get_search_config() -> Result> { - // First, check if user specified a custom path + // First, check if user specified a non-empty custom path if let Ok(custom_path) = env::var("METACALL_INSTALL_PATH") { - // For custom paths, we need to search for any metacall library variant - return Ok(InstallPath { - paths: vec![PathBuf::from(custom_path)], - names: vec![ - "libmetacall.so", - "libmetacalld.so", - "libmetacall.dylib", - "libmetacalld.dylib", - "metacall.lib", - "metacalld.lib", - ], - }); + if !custom_path.is_empty() { + // For custom paths, we need to search for any metacall library variant + return Ok(InstallPath { + paths: vec![PathBuf::from(custom_path)], + names: vec![ + "libmetacall.so", + "libmetacalld.so", + "libmetacall.dylib", + "libmetacalld.dylib", + "metacall.lib", + "metacalld.lib", + ], + }); + } } // Fall back to platform-specific paths @@ -380,3 +383,62 @@ pub fn build() { } } } + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::{Mutex, OnceLock}; + + fn env_lock() -> &'static Mutex<()> { + static LOCK: OnceLock> = OnceLock::new(); + LOCK.get_or_init(|| Mutex::new(())) + } + + fn with_metacall_install_path(value: Option<&str>, callback: impl FnOnce() -> T) -> T { + let _guard = env_lock().lock().unwrap(); + let previous = env::var_os("METACALL_INSTALL_PATH"); + + match value { + Some(path) => env::set_var("METACALL_INSTALL_PATH", path), + None => env::remove_var("METACALL_INSTALL_PATH"), + } + + let result = callback(); + + match previous { + Some(path) => env::set_var("METACALL_INSTALL_PATH", path), + None => env::remove_var("METACALL_INSTALL_PATH"), + } + + result + } + + #[test] + fn ignores_empty_custom_install_path() { + with_metacall_install_path(Some(""), || { + let config = get_search_config().unwrap(); + assert_eq!(config, platform_install_paths().unwrap()); + }); + } + + #[test] + fn honors_non_empty_custom_install_path() { + with_metacall_install_path(Some("/tmp/metacall"), || { + let config = get_search_config().unwrap(); + assert_eq!(config.paths, vec![PathBuf::from("/tmp/metacall")]); + assert!(config.names.contains(&"libmetacall.dylib")); + assert!(config.names.contains(&"libmetacalld.dylib")); + }); + } + + #[cfg(target_os = "macos")] + #[test] + fn macos_searches_release_and_debug_dylibs() { + let config = platform_install_paths().unwrap(); + + assert_eq!( + config.names, + vec!["libmetacall.dylib", "libmetacalld.dylib"] + ); + } +}