Skip to content

Commit

Permalink
feat(dir): Allow in-source dir fixtures
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Dec 16, 2024
1 parent 5de5c1f commit 7863019
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 6 deletions.
55 changes: 54 additions & 1 deletion crates/snapbox/src/dir/fixture.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Collection of files
pub trait DirFixture {
pub trait DirFixture: std::fmt::Debug {
/// Initialize a test fixture directory `root`
fn write_to_path(&self, root: &std::path::Path) -> Result<(), crate::assert::Error>;
}
Expand Down Expand Up @@ -59,3 +59,56 @@ impl DirFixture for String {
std::path::Path::new(self).write_to_path(root)
}
}

impl<P, S> DirFixture for &[(P, S)]
where
P: AsRef<std::path::Path>,
P: std::fmt::Debug,
S: AsRef<[u8]>,
S: std::fmt::Debug,
{
fn write_to_path(&self, root: &std::path::Path) -> Result<(), crate::assert::Error> {
let root = super::ops::canonicalize(root)
.map_err(|e| format!("Failed to canonicalize {}: {}", root.display(), e))?;

for (path, content) in self.iter() {
let rel_path = path.as_ref();
let path = root.join(rel_path);
let path = super::ops::normalize_path(&path);
if !path.starts_with(&root) {
return Err(crate::assert::Error::new(format!(
"Fixture {} is for outside of the target root",
rel_path.display(),
)));
}

let content = content.as_ref();

if let Some(dir) = path.parent() {
std::fs::create_dir_all(dir).map_err(|e| {
format!(
"Failed to create fixture directory {}: {}",
dir.display(),
e
)
})?;
}
std::fs::write(&path, &content)

Check failure

Code scanning / clippy

the borrowed expression implements the required traits Error

the borrowed expression implements the required traits

Check failure

Code scanning / clippy

the borrowed expression implements the required traits Error

the borrowed expression implements the required traits
.map_err(|e| format!("Failed to write fixture {}: {}", path.display(), e))?;
}
Ok(())
}
}

impl<const N: usize, P, S> DirFixture for [(P, S); N]
where
P: AsRef<std::path::Path>,
P: std::fmt::Debug,
S: AsRef<[u8]>,
S: std::fmt::Debug,
{
fn write_to_path(&self, root: &std::path::Path) -> Result<(), crate::assert::Error> {
let s: &[(P, S)] = self;
s.write_to_path(root)
}
}
44 changes: 44 additions & 0 deletions crates/snapbox/src/dir/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,50 @@ pub fn strip_trailing_slash(path: &std::path::Path) -> &std::path::Path {
path.components().as_path()
}

/// Normalize a path, removing things like `.` and `..`.
///
/// CAUTION: This does not resolve symlinks (unlike
/// [`std::fs::canonicalize`]). This may cause incorrect or surprising
/// behavior at times. This should be used carefully. Unfortunately,
/// [`std::fs::canonicalize`] can be hard to use correctly, since it can often
/// fail, or on Windows returns annoying device paths. This is a problem Cargo
/// needs to improve on.
pub(crate) fn normalize_path(path: &std::path::Path) -> std::path::PathBuf {
use std::path::Component;

let mut components = path.components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
components.next();
std::path::PathBuf::from(c.as_os_str())
} else {
std::path::PathBuf::new()
};

for component in components {
match component {
Component::Prefix(..) => unreachable!(),
Component::RootDir => {
ret.push(Component::RootDir);
}
Component::CurDir => {}
Component::ParentDir => {
if ret.ends_with(Component::ParentDir) {
ret.push(Component::ParentDir);
} else {
let popped = ret.pop();
if !popped && !ret.has_root() {
ret.push(Component::ParentDir);
}
}
}
Component::Normal(c) => {
ret.push(c);
}
}
}
ret
}

pub(crate) fn display_relpath(path: impl AsRef<std::path::Path>) -> String {
let path = path.as_ref();
let relpath = if let Ok(cwd) = std::env::current_dir() {
Expand Down
6 changes: 1 addition & 5 deletions crates/snapbox/src/dir/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ impl DirRoot {
return Err("Sandboxing is disabled".into());
}
DirRootInner::MutablePath(path) | DirRootInner::MutableTemp { path, .. } => {
crate::debug!(
"Initializing {} from {}",
path.display(),
template_root.display()
);
crate::debug!("Initializing {} from {:?}", path.display(), template);
template.write_to_path(path)?;
}
}
Expand Down

0 comments on commit 7863019

Please sign in to comment.