Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File inclusion with an explicit destination path #11

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions assay-proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use syn::{
};

struct AssayAttribute {
include: Option<Vec<String>>,
include: Option<Vec<(String, Option<String>)>>,
should_panic: bool,
env: Option<Vec<(String, String)>>,
setup: Option<Expr>,
Expand Down Expand Up @@ -48,7 +48,29 @@ impl Parse for AssayAttribute {
Expr::Lit(ExprLit {
lit: Lit::Str(lit_str),
..
}) => Some(lit_str.value()),
}) => {
let value = lit_str.value();
Some((value, None))
}
Expr::Tuple(tuple) => {
let mut elements = Vec::new();
for e in tuple.elems.into_iter() {
if let Expr::Lit(ExprLit {
lit: Lit::Str(lit_str),
..
}) = e
{
elements.push(lit_str.value());
} else {
return None;
}
}
if elements.len() == 2 {
Some((elements[0].clone(), Some(elements[1].clone())))
} else {
None
}
}
_ => None,
})
.collect(),
Expand Down Expand Up @@ -112,10 +134,14 @@ pub fn assay(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut out = quote! {
let fs = assay::PrivateFS::new()?;
};
for file in include {
for (source_path, destination_path) in include {
let destination_fragment = match destination_path {
None => quote!(std::option::Option::<::std::path::PathBuf>::None),
Some(p) => quote!(std::option::Option::Some(#p)),
};
out = quote! {
#out
fs.include(#file)?;
fs.include(#source_path, #destination_fragment)?;
};
}
out
Expand Down
72 changes: 51 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ pub use pretty_assertions_sorted::{assert_eq, assert_eq_sorted, assert_ne};
#[doc(hidden)]
pub use rusty_fork::{fork, rusty_fork_id, rusty_fork_test_name, ChildWrapper};

use std::fs::create_dir_all;
use std::{
env,
error::Error,
fs::{copy, create_dir_all},
path::{Component, Path, PathBuf},
fs::copy,
path::{Path, PathBuf},
};
use tempfile::{Builder, TempDir};

Expand All @@ -47,39 +48,68 @@ impl PrivateFS {
})
}

pub fn include(&self, path: impl AsRef<Path>) -> Result<(), Box<dyn Error>> {
pub fn include<S, D>(
&self,
source_path: S,
destination_path: Option<D>,
) -> Result<(), Box<dyn Error>>
where
S: AsRef<Path>,
D: AsRef<Path>,
{
// Get our pathbuf to the file to include
let mut inner_path = path.as_ref().to_owned();
let mut inner_path = source_path.as_ref().to_owned();

// If the path given is not absolute then it's relative to the dir we
// ran the test from
let is_relative = inner_path.is_relative();
if is_relative {
inner_path = self.ran_from.join(&path);
inner_path = self.ran_from.join(&source_path);
}

if !inner_path.is_file() {
panic!(
"The source path passed to `#[include()]` must point to a file. {:?} is not a file.",
inner_path
);
}

// Get our working directory
let dir = self.directory.path().to_owned();

// Make the relative path of the file in relation to our temp file
// system based on if it was absolute or not
let relative = if !is_relative {
inner_path
.components()
.filter(|c| *c != Component::RootDir)
.collect::<PathBuf>()
} else {
path.as_ref().into()
let destination_path = match destination_path {
None => {
// If the destination path is unspecified, we mount the file in the root directory
// of the test's private filesystem
match inner_path.file_name() {
Some(filename) => dir.join(filename),
None => {
panic!(
"Failed to extract the filename from the source path, {:?}.",
inner_path
)
}
}
}
Some(p) => {
let p = p.as_ref();
if !p.is_relative() {
panic!(
"The destination path for included files must be a relative path. {:?} isn't.",
p
);
}
// If the relative path to the file includes parent directories create
// them
if let Some(parent) = p.parent() {
create_dir_all(dir.join(parent))?;
}
dir.join(p)
}
};

// If the relative path to the file includes parent directories create
// them
if let Some(parent) = relative.parent() {
create_dir_all(dir.join(parent))?;
}

// Copy the file over from the file system into the temp file system
copy(inner_path, dir.join(relative))?;
copy(inner_path, destination_path)?;

Ok(())
}
Expand Down
9 changes: 5 additions & 4 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ fn private_2() {
assert_eq!("This is a test\nprivate 2\n", &fs::read_to_string("test")?);
}

#[assay(include = ["Cargo.toml", "src/lib.rs"])]
#[assay(include = ["Cargo.toml", "src/lib.rs", ("HOW_TO_USE.md", "docs/GUIDE.md")])]
fn include() {
assert!(fs::metadata("src/lib.rs")?.is_file());
assert!(fs::metadata("lib.rs")?.is_file());
assert!(fs::metadata("Cargo.toml")?.is_file());
assert!(fs::metadata("docs/GUIDE.md")?.is_file());
}

#[assay(should_panic)]
Expand Down Expand Up @@ -95,7 +96,7 @@ fn setup_teardown_test_2() {

#[assay(
setup = setup_func_2(),
include = ["Cargo.toml", "src/lib.rs"],
include = ["Cargo.toml", ("src/lib.rs", "src/lib.rs")],
env = [
("GOODBOY", "Bukka"),
("BADDOGS", "false")
Expand Down Expand Up @@ -133,7 +134,7 @@ async fn one_test_to_call_it_all_2() {
assert_eq!(env::var("BADDOGS")?, "false");
assert_eq!(fs::read_to_string("setup")?, "Value: 5");
assert!(PathBuf::from("Cargo.toml").exists());
assert!(PathBuf::from("src/lib.rs").exists());
assert!(PathBuf::from("lib.rs").exists());

// Removing this actually causes the test to fail
panic!();
Expand Down