Skip to content

Commit 3aa38c3

Browse files
authored
test: Introduce some unit tests for the lib (#31)
* add tempdir dependency * improve docstring and add test for create_package_marker * add test for copy function * add test for install_binaries * add test for install_binaries for arch-specific installation * test install binaries for different lib variants * add test for install files from metadata * revert temporary comments
1 parent ab7e75f commit 3aa38c3

File tree

2 files changed

+214
-2
lines changed

2 files changed

+214
-2
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ anyhow = "1"
1717
cargo-manifest = "0.17"
1818
pico-args = "0.4"
1919

20+
[dev-dependencies]
21+
tempfile = { version = "3" }
22+
2023
# The profile that 'cargo dist' will build with
2124
[profile.dist]
2225
inherits = "release"

src/lib.rs

Lines changed: 211 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,15 @@ pub fn cargo(args: &[OsString], verb: &str) -> Result<Option<i32>> {
125125
Ok(exit_status.code())
126126
}
127127

128-
/// This is comparable to ament_index_register_resource() in CMake
128+
/// Create an ament resource index marker file for a package
129+
///
130+
/// This function registers a package to ament by creating an empty marker file at
131+
/// `share/ament_index/resource_index` with the package name as filename.
132+
///
133+
/// The presence of this file is used by ament and colcon to discover installed packages and other resources.
134+
/// For more information:
135+
/// - Design doc: https://github.com/ament/ament_cmake/blob/2366f15479e37d552d4e225f09ccef1c6ccc8c4e/ament_cmake_core/doc/resource_index.md
136+
/// - Reference implementation of CMake: https://github.com/ament/ament_cmake/blob/2366f15479e37d552d4e225f09ccef1c6ccc8c4e/ament_cmake_core/cmake/index/ament_index_register_resource.cmake
129137
pub fn create_package_marker(
130138
install_base: impl AsRef<Path>,
131139
marker_dir: &str,
@@ -150,7 +158,7 @@ pub fn create_package_marker(
150158
Ok(())
151159
}
152160

153-
/// Copies files or directories.
161+
/// Copies files or directories recursively.
154162
fn copy(src: impl AsRef<Path>, dest_dir: impl AsRef<Path>) -> Result<()> {
155163
let src = src.as_ref();
156164
let dest = dest_dir.as_ref().join(src.file_name().unwrap());
@@ -349,3 +357,204 @@ pub fn install_files_from_metadata(
349357
}
350358
Ok(())
351359
}
360+
361+
#[cfg(test)]
362+
mod tests {
363+
use super::*;
364+
use std::collections::HashMap;
365+
use std::fs::File;
366+
use std::io::Write;
367+
use tempfile::tempdir;
368+
369+
#[test]
370+
fn test_create_package_marker() -> Result<()> {
371+
let tmp = tempdir()?;
372+
let install_base = tmp.path();
373+
374+
create_package_marker(install_base, "packages", "test_package")?;
375+
376+
let marker_path =
377+
install_base.join("share/ament_index/resource_index/packages/test_package");
378+
379+
assert!(marker_path.exists());
380+
assert!(marker_path.is_file());
381+
Ok(())
382+
}
383+
384+
#[test]
385+
fn test_copy_recursive() -> Result<()> {
386+
let tmp = tempdir()?;
387+
let src_dir = tmp.path().join("src_folder");
388+
let dest_dir = tmp.path().join("dest_folder");
389+
390+
std::fs::create_dir_all(src_dir.join("sub"))?;
391+
File::create(src_dir.join("file.txt"))?.write_all(b"hello")?;
392+
File::create(src_dir.join("sub/inner.txt"))?.write_all(b"world")?;
393+
394+
std::fs::create_dir_all(&dest_dir)?;
395+
396+
copy(&src_dir, &dest_dir)?;
397+
398+
assert!(dest_dir.join("src_folder/file.txt").exists());
399+
assert!(dest_dir.join("src_folder/sub/inner.txt").exists());
400+
Ok(())
401+
}
402+
403+
#[test]
404+
fn test_install_binaries_feature_filtering() -> Result<()> {
405+
let tmp = tempdir()?;
406+
let build_base = tmp.path().join("target");
407+
let install_base = tmp.path().join("install");
408+
let profile = "debug";
409+
410+
// Create dummy binaries in build dir. One of them requires a feature that wasn't used during
411+
// compilation and should therefore not be installed
412+
let bin_dir = build_base.join(profile);
413+
std::fs::create_dir_all(&bin_dir)?;
414+
File::create(bin_dir.join("my_bin"))?;
415+
File::create(bin_dir.join("skipped_bin"))?;
416+
417+
let mut features = HashSet::new();
418+
features.insert("required_feat".to_string());
419+
420+
let binaries = vec![
421+
Product {
422+
name: Some("my_bin".to_string()),
423+
required_features: vec!["required_feat".to_string()],
424+
..Default::default()
425+
},
426+
Product {
427+
name: Some("skipped_bin".to_string()),
428+
required_features: vec!["missing_feat".to_string()],
429+
..Default::default()
430+
},
431+
];
432+
433+
install_binaries(
434+
&install_base,
435+
&build_base,
436+
"my_package",
437+
profile,
438+
None,
439+
&features,
440+
&binaries,
441+
)?;
442+
443+
assert!(install_base.join("lib/my_package/my_bin").exists());
444+
assert!(!install_base.join("lib/my_package/skipped_bin").exists());
445+
446+
Ok(())
447+
}
448+
449+
#[test]
450+
fn test_install_binaries_with_arch() -> Result<()> {
451+
let tmp = tempdir()?;
452+
let build_base = tmp.path().join("target");
453+
let install_base = tmp.path().join("install");
454+
let package_name = "arch_test";
455+
let profile = "debug";
456+
let arch = "x86_64-unknown-linux-gnu";
457+
458+
let src_dir_x86 = build_base.join(arch).join(profile);
459+
let src_dir_aarch = build_base.join("aarch64-unknown-linux-gnu").join(profile);
460+
std::fs::create_dir_all(&src_dir_x86)?;
461+
std::fs::create_dir_all(&src_dir_aarch)?;
462+
463+
std::fs::write(src_dir_x86.join("libarch_test.so"), "x86")?;
464+
std::fs::write(src_dir_aarch.join("libarch_test.so"), "aarch")?;
465+
466+
install_binaries(
467+
&install_base,
468+
&build_base,
469+
package_name,
470+
profile,
471+
Some(arch),
472+
&HashSet::new(),
473+
&[],
474+
)?;
475+
476+
let dest_file = install_base
477+
.join("lib")
478+
.join(package_name)
479+
.join("libarch_test.so");
480+
481+
assert!(dest_file.exists());
482+
483+
let installed_content = std::fs::read_to_string(dest_file)?;
484+
assert_eq!(installed_content, "x86");
485+
486+
Ok(())
487+
}
488+
489+
#[test]
490+
fn test_install_binaries_lib_variants() -> Result<()> {
491+
let tmp = tempdir()?;
492+
let build_base = tmp.path().join("target");
493+
let install_base = tmp.path().join("install");
494+
let package_name = "my_rust_lib";
495+
let profile = "release";
496+
497+
let src_dir = build_base.join(profile);
498+
std::fs::create_dir_all(&src_dir)?;
499+
500+
let so_path = src_dir.join("libmy_rust_lib.so");
501+
let a_path = src_dir.join("libmy_rust_lib.a");
502+
let dll_path = src_dir.join("my_rust_lib.dll");
503+
let lib_path = src_dir.join("my_rust_lib.lib");
504+
let dylib_path = src_dir.join("libmy_rust_lib.dylib");
505+
506+
File::create(&so_path)?;
507+
File::create(&a_path)?;
508+
File::create(&dll_path)?;
509+
File::create(&lib_path)?;
510+
File::create(&dylib_path)?;
511+
512+
install_binaries(
513+
&install_base,
514+
&build_base,
515+
package_name,
516+
profile,
517+
None,
518+
&HashSet::new(),
519+
&[],
520+
)?;
521+
522+
let dest_dir = install_base.join("lib").join(package_name);
523+
524+
assert!(dest_dir.join("libmy_rust_lib.so").exists());
525+
assert!(dest_dir.join("libmy_rust_lib.a").exists());
526+
assert!(dest_dir.join("my_rust_lib.dll").exists());
527+
assert!(dest_dir.join("my_rust_lib.lib").exists());
528+
assert!(dest_dir.join("libmy_rust_lib.dylib").exists());
529+
530+
Ok(())
531+
}
532+
533+
#[test]
534+
fn test_install_files_from_metadata() -> Result<()> {
535+
let tmp = tempdir()?;
536+
let package_path = tmp.path().join("pkg");
537+
let install_base = tmp.path().join("install");
538+
539+
std::fs::create_dir_all(package_path.join("launch"))?;
540+
File::create(package_path.join("launch/robot.py"))?;
541+
542+
/* Create serialized metadata akin to:
543+
```toml
544+
[package.metadata.ros]
545+
install_to_share = ["launch"]
546+
```
547+
*/
548+
let mut metadata_table_entries: HashMap<String, Value> = HashMap::new();
549+
metadata_table_entries.insert(
550+
String::from("ros"),
551+
Value::from(HashMap::from([("install_to_share", vec!["launch"])])),
552+
);
553+
let metadata_table = cargo_manifest::Value::from(metadata_table_entries);
554+
555+
install_files_from_metadata(&install_base, &package_path, "pkg", Some(&metadata_table))?;
556+
557+
assert!(install_base.join("share/pkg/launch/robot.py").exists());
558+
Ok(())
559+
}
560+
}

0 commit comments

Comments
 (0)