use cargo_toml::Manifest;
use std::fs;
use std::path::{Path, PathBuf};
pub fn get_project_name(project_root: &Path) -> Option<String> {
let cargo_toml = project_root.join("Cargo.toml");
let content = fs::read_to_string(&cargo_toml).ok()?;
let manifest = Manifest::from_slice(content.as_bytes()).ok()?;
if let Some(package) = &manifest.package {
return Some(package.name.clone());
}
None
}
pub fn find_project_root(binary_path: &Path) -> Result<PathBuf, String> {
let mut current = binary_path.parent();
while let Some(dir) = current {
let cargo_toml = dir.join("Cargo.toml");
if cargo_toml.exists() {
return Ok(dir.to_path_buf());
}
current = dir.parent();
}
Err(format!(
"Cannot find project root for {}",
binary_path.display()
))
}
pub fn derive_crate_src_path(binary_path: &Path) -> Option<String> {
let file_stem = binary_path.file_stem()?.to_str()?;
let is_library_artifact = binary_path.extension().is_some_and(|ext| {
ext == "dylib" || ext == "so" || ext == "dll" || ext == "rlib" || ext == "a" || ext == "lib"
});
let binary_name = if is_library_artifact {
file_stem.strip_prefix("lib").unwrap_or(file_stem)
} else {
file_stem
};
let mut current = binary_path.parent();
while let Some(dir) = current {
let cargo_toml = dir.join("Cargo.toml");
if cargo_toml.exists() {
if is_library_artifact {
if let Some(path) = find_lib_src_path(dir, binary_name) {
return Some(path);
}
} else {
if let Some(path) = find_bin_src_path(dir, binary_name) {
return Some(path);
}
}
let example_src = dir.join("examples").join(binary_name).join("src");
if example_src.exists() {
return Some(format!("examples/{}/src/", binary_name));
}
let member_src = dir.join(binary_name).join("src");
if member_src.exists() {
return Some(format!("{}/src/", binary_name));
}
let root_src = dir.join("src");
if root_src.exists() {
return Some("src/".to_string());
}
}
current = dir.parent();
}
None
}
pub fn expand_workspace_members(workspace_root: &Path, member_pattern: &str) -> Vec<PathBuf> {
if member_pattern.contains('*') {
let base = member_pattern.trim_end_matches("/*");
let base_path = workspace_root.join(base);
if base_path.is_dir() {
fs::read_dir(&base_path)
.ok()
.map(|entries| {
entries
.filter_map(|e| e.ok())
.filter(|e| e.path().is_dir())
.map(|e| e.path())
.collect()
})
.unwrap_or_default()
} else {
vec![]
}
} else {
vec![workspace_root.join(member_pattern)]
}
}
pub fn find_bin_src_path(workspace_root: &Path, bin_name: &str) -> Option<String> {
let cargo_toml = workspace_root.join("Cargo.toml");
let content = fs::read_to_string(&cargo_toml).ok()?;
let manifest = Manifest::from_slice(content.as_bytes()).ok()?;
if let Some(path) = check_manifest_for_binary(&manifest, bin_name) {
return Some(path);
}
if manifest.bin.is_empty()
&& let Some(package) = &manifest.package
&& (package.name == bin_name || package.name.replace('-', "_") == bin_name)
&& workspace_root.join("src").join("main.rs").exists()
{
return Some("src/".to_string());
}
let workspace = manifest.workspace.as_ref()?;
for member_pattern in &workspace.members {
let member_paths = expand_workspace_members(workspace_root, member_pattern);
for member_path in member_paths {
let member_cargo_toml = member_path.join("Cargo.toml");
if !member_cargo_toml.exists() {
continue;
}
if let Ok(member_content) = fs::read_to_string(&member_cargo_toml)
&& let Ok(member_manifest) = Manifest::from_slice(member_content.as_bytes())
{
for bin in &member_manifest.bin {
let manifest_bin_name = bin
.name
.clone()
.or_else(|| member_manifest.package.as_ref().map(|p| p.name.clone()))
.unwrap_or_default();
if manifest_bin_name == bin_name
|| manifest_bin_name.replace('-', "_") == bin_name
{
if let Ok(rel_path) = member_path.strip_prefix(workspace_root) {
let src_dir = bin_source_dir_from_path(bin.path.as_ref());
return Some(format!("{}/{}/", rel_path.display(), src_dir.display()));
}
}
}
if member_manifest.bin.is_empty()
&& let Some(package) = &member_manifest.package
{
let pkg_name = &package.name;
if pkg_name == bin_name || pkg_name.replace('-', "_") == bin_name {
if member_path.join("src").join("main.rs").exists() {
if let Ok(rel_path) = member_path.strip_prefix(workspace_root) {
return Some(format!("{}/src/", rel_path.display()));
}
}
}
}
}
}
}
None
}
fn bin_source_dir_from_path(bin_path: Option<&String>) -> PathBuf {
bin_path
.and_then(|p| Path::new(p).parent().map(|p| p.to_path_buf()))
.filter(|p| !p.as_os_str().is_empty())
.unwrap_or_else(|| PathBuf::from("src"))
}
fn check_manifest_for_binary(manifest: &Manifest, bin_name: &str) -> Option<String> {
for bin in &manifest.bin {
let manifest_bin_name = bin
.name
.clone()
.or_else(|| manifest.package.as_ref().map(|p| p.name.clone()))
.unwrap_or_default();
if manifest_bin_name == bin_name || manifest_bin_name.replace('-', "_") == bin_name {
let src_dir = bin_source_dir_from_path(bin.path.as_ref());
return Some(format!("{}/", src_dir.display()));
}
}
None
}
pub fn find_lib_crate_dir(workspace_root: &Path, lib_name: &str) -> Option<PathBuf> {
let cargo_toml = workspace_root.join("Cargo.toml");
let content = fs::read_to_string(&cargo_toml).ok()?;
let manifest = Manifest::from_slice(content.as_bytes()).ok()?;
let workspace = manifest.workspace.as_ref()?;
for member_pattern in &workspace.members {
let member_paths = expand_workspace_members(workspace_root, member_pattern);
for member_path in member_paths {
let member_cargo_toml = member_path.join("Cargo.toml");
if !member_cargo_toml.exists() {
continue;
}
if let Ok(member_content) = fs::read_to_string(&member_cargo_toml)
&& let Ok(member_manifest) = Manifest::from_slice(member_content.as_bytes())
&& let Some(lib) = &member_manifest.lib
{
let manifest_lib_name = lib
.name
.clone()
.or_else(|| member_manifest.package.as_ref().map(|p| p.name.clone()))
.unwrap_or_default();
if manifest_lib_name == lib_name || manifest_lib_name.replace('-', "_") == lib_name
{
return Some(member_path);
}
}
}
}
None
}
pub fn find_lib_src_path(workspace_root: &Path, lib_name: &str) -> Option<String> {
let cargo_toml = workspace_root.join("Cargo.toml");
let content = fs::read_to_string(&cargo_toml).ok()?;
let manifest = Manifest::from_slice(content.as_bytes()).ok()?;
let workspace = manifest.workspace.as_ref()?;
for member_pattern in &workspace.members {
let member_paths = expand_workspace_members(workspace_root, member_pattern);
for member_path in member_paths {
let member_cargo_toml = member_path.join("Cargo.toml");
if !member_cargo_toml.exists() {
continue;
}
if let Ok(member_content) = fs::read_to_string(&member_cargo_toml)
&& let Ok(member_manifest) = Manifest::from_slice(member_content.as_bytes())
&& let Some(lib) = &member_manifest.lib
{
let manifest_lib_name = lib
.name
.clone()
.or_else(|| member_manifest.package.as_ref().map(|p| p.name.clone()))
.unwrap_or_default();
if manifest_lib_name == lib_name || manifest_lib_name.replace('-', "_") == lib_name
{
if let Ok(rel_path) = member_path.strip_prefix(workspace_root) {
return Some(format!("{}/src/", rel_path.display()));
}
}
}
}
}
None
}
pub fn detect_library_type(binary_path: &Path) -> Option<String> {
let file_stem = binary_path.file_stem()?.to_str()?;
let lib_name = file_stem.strip_prefix("lib")?;
let mut current = binary_path.parent();
while let Some(dir) = current {
let cargo_toml = dir.join("Cargo.toml");
if cargo_toml.exists()
&& let Ok(content) = fs::read_to_string(&cargo_toml)
&& let Ok(manifest) = Manifest::from_slice(content.as_bytes())
{
if let Some(workspace) = &manifest.workspace {
for member_pattern in &workspace.members {
let member_paths = expand_workspace_members(dir, member_pattern);
for member_path in member_paths {
if let Some(lib_type) = check_member_lib_type(&member_path, lib_name) {
return Some(lib_type);
}
}
}
}
if let Some(lib) = &manifest.lib {
let manifest_lib_name = lib
.name
.clone()
.or_else(|| manifest.package.as_ref().map(|p| p.name.clone()))
.unwrap_or_default();
if manifest_lib_name == lib_name || manifest_lib_name.replace('-', "_") == lib_name
{
for crate_type in &lib.crate_type {
if crate_type == "cdylib" {
return Some("cdylib".to_string());
}
if crate_type == "dylib" {
return Some("dylib".to_string());
}
}
}
}
}
current = dir.parent();
}
None
}
pub fn find_binary(dir: &Path, name: &str) -> Option<PathBuf> {
let path = dir.join(name);
if path.exists() {
return Some(path);
}
#[cfg(windows)]
{
let exe_path = path.with_extension("exe");
if exe_path.exists() {
return Some(exe_path);
}
}
None
}
pub fn find_library(dir: &Path, name: &str) -> Option<PathBuf> {
let lib_name = name.replace('-', "_");
let dylib = dir.join(format!("lib{}.dylib", lib_name));
if dylib.exists() {
return Some(dylib);
}
let so = dir.join(format!("lib{}.so", lib_name));
if so.exists() {
return Some(so);
}
let rlib = dir.join(format!("lib{}.rlib", lib_name));
if rlib.exists() {
return Some(rlib);
}
let staticlib = dir.join(format!("lib{}.a", lib_name));
if staticlib.exists() {
return Some(staticlib);
}
None
}
fn check_member_lib_type(member_path: &Path, lib_name: &str) -> Option<String> {
let cargo_toml = member_path.join("Cargo.toml");
if !cargo_toml.exists() {
return None;
}
let content = fs::read_to_string(&cargo_toml).ok()?;
let manifest = Manifest::from_slice(content.as_bytes()).ok()?;
if let Some(lib) = &manifest.lib {
let manifest_lib_name = lib
.name
.clone()
.or_else(|| manifest.package.as_ref().map(|p| p.name.clone()))
.unwrap_or_default();
if manifest_lib_name == lib_name || manifest_lib_name.replace('-', "_") == lib_name {
for crate_type in &lib.crate_type {
if crate_type == "cdylib" {
return Some("cdylib".to_string());
}
if crate_type == "dylib" {
return Some("dylib".to_string());
}
}
}
}
None
}
#[derive(Debug)]
pub struct WorkspaceMember {
pub name: String,
pub path: PathBuf,
pub binaries: Vec<PathBuf>,
}
pub(crate) fn find_target_dir() -> Result<PathBuf, String> {
let mut current =
std::env::current_dir().map_err(|e| format!("Cannot get current dir: {}", e))?;
loop {
let target_dir = current.join("target/debug");
if target_dir.exists() {
return Ok(target_dir);
}
let cargo_toml = current.join("Cargo.toml");
if cargo_toml.exists()
&& let Ok(content) = fs::read_to_string(&cargo_toml)
&& content.contains("[workspace]")
{
return Err("target/debug/ directory not found. Run 'cargo build' first.".to_string());
}
if let Some(parent) = current.parent() {
current = parent.to_path_buf();
} else {
break;
}
}
Err("target/debug/ directory not found. Run 'cargo build' first.".to_string())
}
pub(crate) fn is_workspace_root() -> bool {
let cargo_toml_path = PathBuf::from("Cargo.toml");
if !cargo_toml_path.exists() {
return false;
}
let Ok(content) = fs::read_to_string(&cargo_toml_path) else {
return false;
};
let Ok(manifest) = Manifest::from_slice(content.as_bytes()) else {
return false;
};
manifest.workspace.is_some()
}
pub(crate) fn find_workspace_members() -> Result<Option<Vec<WorkspaceMember>>, String> {
let cargo_toml_path = PathBuf::from("Cargo.toml");
if !cargo_toml_path.exists() {
return Ok(None);
}
let cargo_toml_content = fs::read_to_string(&cargo_toml_path)
.map_err(|e| format!("Failed to read Cargo.toml: {}", e))?;
let manifest = Manifest::from_slice(cargo_toml_content.as_bytes())
.map_err(|e| format!("Failed to parse Cargo.toml: {}", e))?;
if manifest.workspace.is_none() {
return Ok(None);
}
let workspace = manifest.workspace.as_ref().unwrap();
let target_dir = PathBuf::from("target/debug");
if !target_dir.exists() {
return Err("target/debug/ directory not found. Run 'cargo build' first.".to_string());
}
let mut members = Vec::new();
if let Some(pkg) = &manifest.package {
let pkg_name = pkg.name.clone();
let mut root_manifest = manifest.clone();
let _ = root_manifest.complete_from_path_and_workspace::<toml::Value>(
&cargo_toml_path,
None::<(&Manifest<toml::Value>, &Path)>, );
let binaries = collect_binaries_from_manifest(&root_manifest, &pkg_name, &target_dir);
if !binaries.is_empty() {
members.push(WorkspaceMember {
name: pkg_name,
path: PathBuf::from("."),
binaries,
});
}
}
let cwd = PathBuf::from(".");
for member_pattern in &workspace.members {
for member_path in expand_workspace_members(&cwd, member_pattern) {
let member_cargo_toml = member_path.join("Cargo.toml");
if !member_cargo_toml.exists() {
continue;
}
if let Ok(content) = fs::read_to_string(&member_cargo_toml)
&& let Ok(mut member_manifest) = Manifest::from_slice(content.as_bytes())
&& let Some(pkg) = &member_manifest.package
{
let pkg_name = pkg.name.clone();
let _ = member_manifest.complete_from_path_and_workspace(
&member_cargo_toml,
Some((&manifest, &cargo_toml_path)),
);
let binaries =
collect_binaries_from_manifest(&member_manifest, &pkg_name, &target_dir);
if !binaries.is_empty() {
members.push(WorkspaceMember {
name: pkg_name,
path: member_path,
binaries,
});
}
}
}
}
if members.is_empty() {
return Err("No binary targets found in workspace. Run 'cargo build' first.".to_string());
}
Ok(Some(members))
}
pub(crate) fn collect_binaries_from_manifest(
manifest: &Manifest,
pkg_name: &str,
target_dir: &Path,
) -> Vec<PathBuf> {
let mut binaries = Vec::new();
for bin in &manifest.bin {
let bin_name = bin.name.as_deref().unwrap_or(pkg_name);
if let Some(bin_path) = find_binary(target_dir, bin_name) {
binaries.push(bin_path);
}
}
if manifest.lib.is_some() {
let lib_name = manifest
.lib
.as_ref()
.and_then(|l| l.name.clone())
.unwrap_or_else(|| pkg_name.replace('-', "_"));
if let Some(lib_path) = find_library(target_dir, &lib_name) {
binaries.push(lib_path);
}
}
binaries
}
pub(crate) fn find_workspace_binaries(manifest: &Manifest) -> Result<Vec<PathBuf>, String> {
let workspace = manifest
.workspace
.as_ref()
.ok_or("No workspace section found")?;
let target_dir = PathBuf::from("target/debug");
if !target_dir.exists() {
return Err("target/debug/ directory not found. Run 'cargo build' first.".to_string());
}
let mut binaries = Vec::new();
let cwd = PathBuf::from(".");
for member_pattern in &workspace.members {
for member_path in expand_workspace_members(&cwd, member_pattern) {
let member_cargo_toml = member_path.join("Cargo.toml");
if !member_cargo_toml.exists() {
continue;
}
if let Ok(content) = fs::read_to_string(&member_cargo_toml)
&& let Ok(member_manifest) = Manifest::from_slice(content.as_bytes())
&& let Some(pkg) = &member_manifest.package
{
let pkg_name = &pkg.name;
for bin in &member_manifest.bin {
let bin_name = bin.name.as_ref().unwrap_or(pkg_name);
let bin_path = target_dir.join(bin_name);
if bin_path.exists() {
binaries.push(bin_path);
}
}
if member_manifest.bin.is_empty() {
let default_bin = target_dir.join(pkg_name);
if default_bin.exists() {
binaries.push(default_bin);
}
}
}
}
}
if binaries.is_empty() {
return Err("No binary targets found in workspace. Run 'cargo build' first.".to_string());
}
Ok(binaries)
}
pub(crate) fn find_crate_binaries() -> Result<Vec<PathBuf>, String> {
let cargo_toml_path = PathBuf::from("Cargo.toml");
if !cargo_toml_path.exists() {
return Err("No Cargo.toml found in current directory. \
Run jonesy from a crate root or use --bin <path>."
.to_string());
}
let cargo_toml_content = fs::read_to_string(&cargo_toml_path)
.map_err(|e| format!("Failed to read Cargo.toml: {}", e))?;
let manifest = Manifest::from_slice(cargo_toml_content.as_bytes())
.map_err(|e| format!("Failed to parse Cargo.toml: {}", e))?;
if manifest.workspace.is_some() && manifest.package.is_none() {
return find_workspace_binaries(&manifest);
}
let package = manifest
.package
.as_ref()
.ok_or("Cargo.toml has no [package] section")?;
let package_name = &package.name;
let target_dir = find_target_dir()?;
let mut binaries = Vec::new();
for bin in &manifest.bin {
let bin_name = bin.name.as_ref().unwrap_or(package_name);
let bin_path = target_dir.join(bin_name);
if bin_path.exists() {
binaries.push(bin_path);
}
}
if manifest.bin.is_empty() {
let default_bin = target_dir.join(package_name);
if default_bin.exists() {
binaries.push(default_bin);
}
}
let has_library = manifest.lib.is_some() || PathBuf::from("src/lib.rs").exists();
if has_library {
let lib_name = manifest
.lib
.as_ref()
.and_then(|l| l.name.clone())
.unwrap_or_else(|| package_name.replace('-', "_"));
if let Some(lib_path) = find_library(&target_dir, &lib_name) {
binaries.push(lib_path);
}
}
if binaries.is_empty() {
return Err(format!(
"No binary targets found in target/debug/ for package '{}'. \
Run 'cargo build' first.",
package_name
));
}
Ok(binaries)
}
pub(crate) fn find_bin_in_manifest(
bin_name: &str,
manifest: &Manifest,
target_dir: &Path,
) -> Option<PathBuf> {
for bin in &manifest.bin {
let manifest_bin_name = bin
.name
.as_ref()
.or(manifest.package.as_ref().map(|p| &p.name));
if let Some(name) = manifest_bin_name {
if name == bin_name || name.replace('-', "_") == bin_name {
let bin_path = target_dir.join(name);
if bin_path.exists() {
return Some(bin_path);
}
}
}
}
if let Some(pkg) = &manifest.package {
if pkg.name == bin_name || pkg.name.replace('-', "_") == bin_name {
let bin_path = target_dir.join(&pkg.name);
if bin_path.exists() {
return Some(bin_path);
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::{self, File};
use tempfile::TempDir;
#[test]
fn test_bin_source_dir_from_path_none() {
let result = bin_source_dir_from_path(None);
assert_eq!(result, PathBuf::from("src"));
}
#[test]
fn test_bin_source_dir_from_path_with_path() {
let result = bin_source_dir_from_path(Some(&"src/bin/app.rs".to_string()));
assert_eq!(result, PathBuf::from("src/bin"));
}
#[test]
fn test_bin_source_dir_from_path_empty_parent() {
let result = bin_source_dir_from_path(Some(&"main.rs".to_string()));
assert_eq!(result, PathBuf::from("src"));
}
#[test]
fn test_find_project_root_not_found() {
let result = find_project_root(Path::new("/nonexistent/path/to/binary"));
assert!(result.is_err());
}
#[test]
fn test_find_project_root_found() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
File::create(&cargo_toml).unwrap();
let binary_path = temp_dir.path().join("target/debug/myapp");
fs::create_dir_all(binary_path.parent().unwrap()).unwrap();
let result = find_project_root(&binary_path);
assert!(result.is_ok());
assert_eq!(result.unwrap(), temp_dir.path());
}
#[test]
fn test_get_project_name_not_found() {
let result = get_project_name(Path::new("/nonexistent/path"));
assert!(result.is_none());
}
#[test]
fn test_get_project_name_workspace_only() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[workspace]
members = ["crate_a"]
"#,
)
.unwrap();
let result = get_project_name(temp_dir.path());
assert!(result.is_none());
}
#[test]
fn test_get_project_name_with_package() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "my-project"
version = "0.1.0"
"#,
)
.unwrap();
let result = get_project_name(temp_dir.path());
assert_eq!(result, Some("my-project".to_string()));
}
#[test]
fn test_find_binary_not_found() {
let temp_dir = TempDir::new().unwrap();
let result = find_binary(temp_dir.path(), "nonexistent");
assert!(result.is_none());
}
#[test]
fn test_find_binary_found() {
let temp_dir = TempDir::new().unwrap();
let binary_path = temp_dir.path().join("myapp");
File::create(&binary_path).unwrap();
let result = find_binary(temp_dir.path(), "myapp");
assert!(result.is_some());
assert_eq!(result.unwrap(), binary_path);
}
#[test]
fn test_find_library_rlib() {
let temp_dir = TempDir::new().unwrap();
let lib_path = temp_dir.path().join("libmylib.rlib");
File::create(&lib_path).unwrap();
let result = find_library(temp_dir.path(), "mylib");
assert!(result.is_some());
assert_eq!(result.unwrap(), lib_path);
}
#[test]
fn test_find_library_with_dashes() {
let temp_dir = TempDir::new().unwrap();
let lib_path = temp_dir.path().join("libmy_lib.rlib");
File::create(&lib_path).unwrap();
let result = find_library(temp_dir.path(), "my-lib");
assert!(result.is_some());
assert_eq!(result.unwrap(), lib_path);
}
#[test]
fn test_find_library_not_found() {
let temp_dir = TempDir::new().unwrap();
let result = find_library(temp_dir.path(), "nonexistent");
assert!(result.is_none());
}
#[test]
fn test_expand_workspace_member_no_glob() {
let temp_dir = TempDir::new().unwrap();
let result = expand_workspace_members(temp_dir.path(), "crates/mylib");
assert_eq!(result.len(), 1);
assert_eq!(result[0], temp_dir.path().join("crates/mylib"));
}
#[test]
fn test_expand_workspace_member_glob() {
let temp_dir = TempDir::new().unwrap();
let crates_dir = temp_dir.path().join("crates");
fs::create_dir(&crates_dir).unwrap();
fs::create_dir(crates_dir.join("lib_a")).unwrap();
fs::create_dir(crates_dir.join("lib_b")).unwrap();
let result = expand_workspace_members(temp_dir.path(), "crates/*");
assert_eq!(result.len(), 2);
}
#[test]
fn test_expand_workspace_member_glob_no_matches() {
let temp_dir = TempDir::new().unwrap();
let result = expand_workspace_members(temp_dir.path(), "nonexistent/*");
assert!(result.is_empty());
}
#[test]
fn test_derive_crate_src_path_no_cargo_toml() {
let temp_dir = TempDir::new().unwrap();
let binary_path = temp_dir.path().join("target/debug/myapp");
fs::create_dir_all(binary_path.parent().unwrap()).unwrap();
let result = derive_crate_src_path(&binary_path);
assert!(result.is_none());
}
#[test]
fn test_derive_crate_src_path_simple_crate() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "myapp"
version = "0.1.0"
"#,
)
.unwrap();
fs::create_dir(temp_dir.path().join("src")).unwrap();
File::create(temp_dir.path().join("src/main.rs")).unwrap();
let binary_path = temp_dir.path().join("target/debug/myapp");
fs::create_dir_all(binary_path.parent().unwrap()).unwrap();
let result = derive_crate_src_path(&binary_path);
assert_eq!(result, Some("src/".to_string()));
}
#[test]
fn test_derive_crate_src_path_library() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "mylib"
version = "0.1.0"
[lib]
name = "mylib"
"#,
)
.unwrap();
fs::create_dir(temp_dir.path().join("src")).unwrap();
File::create(temp_dir.path().join("src/lib.rs")).unwrap();
let lib_path = temp_dir.path().join("target/debug/libmylib.rlib");
fs::create_dir_all(lib_path.parent().unwrap()).unwrap();
let result = derive_crate_src_path(&lib_path);
assert!(result.is_some());
}
#[test]
fn test_check_member_lib_type_not_found() {
let temp_dir = TempDir::new().unwrap();
let result = check_member_lib_type(temp_dir.path(), "mylib");
assert!(result.is_none());
}
#[test]
fn test_check_member_lib_type_cdylib() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "mylib"
version = "0.1.0"
[lib]
name = "mylib"
crate-type = ["cdylib"]
"#,
)
.unwrap();
let result = check_member_lib_type(temp_dir.path(), "mylib");
assert_eq!(result, Some("cdylib".to_string()));
}
#[test]
fn test_check_member_lib_type_dylib() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "mylib"
version = "0.1.0"
[lib]
name = "mylib"
crate-type = ["dylib"]
"#,
)
.unwrap();
let result = check_member_lib_type(temp_dir.path(), "mylib");
assert_eq!(result, Some("dylib".to_string()));
}
#[test]
fn test_detect_library_type_not_library() {
let result = detect_library_type(Path::new("/target/debug/myapp"));
assert!(result.is_none());
}
#[test]
fn test_find_bin_src_path_not_found() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "other"
version = "0.1.0"
"#,
)
.unwrap();
let result = find_bin_src_path(temp_dir.path(), "myapp");
assert!(result.is_none());
}
#[test]
fn test_find_bin_src_path_simple_crate() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "myapp"
version = "0.1.0"
"#,
)
.unwrap();
fs::create_dir(temp_dir.path().join("src")).unwrap();
File::create(temp_dir.path().join("src/main.rs")).unwrap();
let result = find_bin_src_path(temp_dir.path(), "myapp");
assert_eq!(result, Some("src/".to_string()));
}
#[test]
fn test_find_lib_src_path_not_found() {
let temp_dir = TempDir::new().unwrap();
let cargo_toml = temp_dir.path().join("Cargo.toml");
fs::write(
&cargo_toml,
r#"
[package]
name = "other"
version = "0.1.0"
"#,
)
.unwrap();
let result = find_lib_src_path(temp_dir.path(), "mylib");
assert!(result.is_none());
}
#[test]
fn test_find_bin_in_manifest_no_bins() {
let content = r#"
[package]
name = "my-package"
version = "0.1.0"
"#;
let manifest = Manifest::from_slice(content.as_bytes()).unwrap();
let result = find_bin_in_manifest("nonexistent", &manifest, Path::new("/tmp"));
assert!(result.is_none());
}
#[test]
fn test_collect_binaries_no_bins() {
let content = r#"
[package]
name = "my-package"
version = "0.1.0"
"#;
let manifest = Manifest::from_slice(content.as_bytes()).unwrap();
let target_dir = PathBuf::from("/tmp");
let binaries = collect_binaries_from_manifest(&manifest, "my-package", &target_dir);
assert!(binaries.is_empty());
}
#[test]
fn test_workspace_member_debug() {
let member = WorkspaceMember {
name: "test-crate".to_string(),
path: PathBuf::from("crates/test-crate"),
binaries: vec![PathBuf::from("target/debug/test-crate")],
};
let debug_str = format!("{:?}", member);
assert!(debug_str.contains("test-crate"));
assert!(debug_str.contains("crates/test-crate"));
}
}