use anyhow::Result;
use cap_std::fs::{Dir, File, Permissions};
use cap_std_ext::cap_std;
use cap_std_ext::cmdext::CapStdExtCommandExt;
use cap_std_ext::dirext::CapStdExtDirExt;
use std::io::Write;
use std::os::unix::prelude::PermissionsExt;
use std::path::Path;
use std::{process::Command, sync::Arc};
#[test]
fn take_fd() -> Result<()> {
let mut c = Command::new("/bin/bash");
c.arg("-c");
c.arg("wc -c <&5");
let (r, w) = rustix::io::pipe()?;
let r = Arc::new(r);
let mut w: File = w.into();
c.take_fd_n(r.clone(), 5);
write!(w, "hello world")?;
drop(w);
c.stdout(std::process::Stdio::piped());
let s = c.output()?;
assert!(s.status.success());
assert_eq!(s.stdout.as_slice(), b"11\n");
Ok(())
}
#[test]
fn fchdir() -> Result<()> {
static CONTENTS: &[u8] = b"hello world";
fn new_cmd() -> Command {
let mut c = Command::new("/usr/bin/cat");
c.arg("somefile");
c
}
fn test_cmd(mut c: Command) -> Result<()> {
let st = c.output()?;
if !st.status.success() {
anyhow::bail!("Failed to exec cat");
}
assert_eq!(st.stdout.as_slice(), CONTENTS);
Ok(())
}
let td = Arc::new(cap_tempfile::tempdir(cap_std::ambient_authority())?);
td.write("somefile", CONTENTS)?;
let mut c = new_cmd();
let subdir = td.open_dir(".")?;
c.cwd_dir(subdir.try_clone()?);
test_cmd(c).unwrap();
Ok(())
}
#[test]
fn optionals() -> Result<()> {
let td = cap_tempfile::tempdir(cap_std::ambient_authority())?;
assert!(td.open_optional("bar")?.is_none());
assert!(td.metadata_optional("bar").unwrap().is_none());
assert_eq!(td.remove_file_optional("bar")?, false);
td.write("bar", "testcontents")?;
assert!(td.metadata_optional("bar").unwrap().is_some());
assert!(td.symlink_metadata_optional("bar").unwrap().is_some());
assert_eq!(td.read("bar")?.as_slice(), b"testcontents");
assert_eq!(td.remove_file_optional("bar")?, true);
assert!(td.open_dir_optional("somedir")?.is_none());
td.create_dir("somedir")?;
assert!(td.open_dir_optional("somedir")?.is_some());
Ok(())
}
#[test]
fn ensuredir() -> Result<()> {
let td = cap_tempfile::tempdir(cap_std::ambient_authority())?;
let p = Path::new("somedir");
let b = &cap_std::fs::DirBuilder::new();
assert!(td.metadata_optional(p)?.is_none());
assert!(td.symlink_metadata_optional(p)?.is_none());
assert!(td.ensure_dir_with(p, b).unwrap());
assert!(td.metadata_optional(p)?.is_some());
assert!(td.symlink_metadata_optional(p)?.is_some());
assert_eq!(td.ensure_dir_with(p, b).unwrap(), false);
let p = Path::new("somedir/without/existing-parent");
assert!(td.ensure_dir_with(p, b).is_err());
assert!(td.ensure_dir_with(p.parent().unwrap(), b).unwrap());
assert!(td.ensure_dir_with(p, b).unwrap());
assert_eq!(td.ensure_dir_with(p, b).unwrap(), false);
let p = Path::new("somefile");
td.write(p, "some file contents")?;
assert!(td.ensure_dir_with(p, b).is_err());
let p = Path::new("linksrc");
td.symlink("linkdest", p)?;
assert!(td.metadata(p).is_err());
assert!(td
.symlink_metadata_optional(p)
.unwrap()
.unwrap()
.is_symlink());
assert!(td.ensure_dir_with(p, b).is_err());
td.create_dir("linkdest")?;
assert!(td.ensure_dir_with(p, b).is_err());
assert!(td.metadata_optional(p).unwrap().unwrap().is_dir());
Ok(())
}
#[test]
fn test_remove_all_optional() -> Result<()> {
let td = cap_tempfile::tempdir(cap_std::ambient_authority())?;
let p = Path::new("somedir");
assert_eq!(td.remove_all_optional(p).unwrap(), false);
td.create_dir(p)?;
assert_eq!(td.remove_all_optional(p).unwrap(), true);
let subpath = p.join("foo/bar");
td.create_dir_all(subpath)?;
assert_eq!(td.remove_all_optional(p).unwrap(), true);
td.write(p, "test")?;
assert_eq!(td.remove_all_optional(p).unwrap(), true);
let p = Path::new("linksrc");
td.symlink("linkdest", p)?;
assert_eq!(td.remove_all_optional(p).unwrap(), true);
td.symlink("linkdest", p)?;
assert_eq!(td.remove_all_optional(p).unwrap(), true);
Ok(())
}
fn default_mode(d: &Dir) -> Result<Permissions> {
let f = cap_tempfile::TempFile::new(d)?;
Ok(f.as_file().metadata()?.permissions())
}
#[test]
fn link_tempfile_with() -> Result<()> {
let td = cap_tempfile::tempdir(cap_std::ambient_authority())?;
let p = Path::new("foo");
td.atomic_replace_with(p, |f| writeln!(f, "hello world"))
.unwrap();
assert_eq!(td.read_to_string(p).unwrap().as_str(), "hello world\n");
let default_perms = default_mode(&td)?;
assert_eq!(td.metadata(p)?.permissions(), default_perms);
td.atomic_replace_with(p, |f| writeln!(f, "atomic replacement"))
.unwrap();
assert_eq!(
td.read_to_string(p).unwrap().as_str(),
"atomic replacement\n"
);
let e = td
.atomic_replace_with(p, |f| {
writeln!(f, "should not be written")?;
Err::<(), _>(std::io::Error::new(std::io::ErrorKind::Other, "oops"))
})
.err()
.unwrap();
assert!(e.to_string().contains("oops"));
assert_eq!(
td.read_to_string(p).unwrap().as_str(),
"atomic replacement\n"
);
td.atomic_write(p, "atomic replacement write\n").unwrap();
assert_eq!(
td.read_to_string(p).unwrap().as_str(),
"atomic replacement write\n"
);
assert_eq!(td.metadata(p)?.permissions(), default_perms);
td.atomic_write_with_perms(p, "atomic replacement 3\n", Permissions::from_mode(0o700))
.unwrap();
assert_eq!(
td.read_to_string(p).unwrap().as_str(),
"atomic replacement 3\n"
);
assert_eq!(td.metadata(p)?.permissions().mode() & 0o777, 0o700);
Ok(())
}
#[test]
fn test_timestamps() -> Result<()> {
let td = cap_tempfile::tempdir(cap_std::ambient_authority())?;
let p = Path::new("foo");
td.atomic_replace_with(p, |f| writeln!(f, "hello world"))
.unwrap();
let ts0 = td.metadata(p)?.modified()?;
std::thread::sleep(std::time::Duration::from_secs(1));
let ts1 = td.metadata(p)?.modified()?;
assert_eq!(ts0, ts1);
td.update_timestamps(p).unwrap();
let ts2 = td.metadata(p)?.modified()?;
assert_ne!(ts1, ts2);
assert!(ts2 > ts1);
Ok(())
}