use crate::internal::*;
use IncludeTarget as Target;
use ResolveError as Err;
use SourceFile as Src;
pub fn prepare(
target_str: &str,
target_is_uri: bool,
src_file: &SourceFile,
src_is_primary: bool,
base_dir: Option<Path>,
) -> std::result::Result<IncludeTarget, ResolveError> {
if target_is_uri {
return Ok(Target::Uri(target_str.to_string()));
}
let target = Path::new(target_str);
if src_is_primary && target.is_relative() {
let Some(base_dir) = base_dir else {
return Err(Err::BaseDirRequired);
};
let abspath = base_dir.join(target);
return Ok(Target::FilePath(abspath.to_string()));
}
match src_file {
Src::Path(src) => {
let abspath = if target.is_relative() {
let dir = Path::new(src.dirname());
dir.join(target)
} else {
target
};
Ok(abspath.into())
}
Src::Stdin { .. } => unimplemented!("include from stdin not implemented yet"),
Src::Tmp => unreachable!(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use IncludeTarget::*;
struct TestCase {
name: &'static str,
target_str: &'static str,
target_is_uri: bool,
src_file: SourceFile,
src_is_primary: bool,
base_dir: Option<Path>,
expected: std::result::Result<IncludeTarget, ResolveError>,
}
impl Default for TestCase {
fn default() -> Self {
Self {
name: "",
target_str: "",
target_is_uri: false,
src_file: SourceFile::Tmp,
src_is_primary: true,
base_dir: Some(Path::new("/basedir")),
expected: Err(ResolveError::NotFound),
}
}
}
#[test]
fn resolve_target_filepaths() {
let cases = vec![
TestCase {
name: "relative includes from primary doc are resolved relative to basedir",
src_is_primary: true, base_dir: Some(Path::new("/basedir")),
target_str: "b.adoc",
src_file: SourceFile::Path(Path::new("/basedir/subdir/src.adoc")),
expected: Ok(FilePath("/basedir/b.adoc".to_string())), ..TestCase::default()
},
TestCase {
name: "relative include from primary doc targeting basedir",
target_str: "b.adoc",
src_file: SourceFile::Path(Path::new("/basedir/src.adoc")),
expected: Ok(FilePath("/basedir/b.adoc".to_string())),
..TestCase::default()
},
TestCase {
name: "non-primary relative include",
src_is_primary: false, target_str: "other.adoc",
src_file: SourceFile::Path(Path::new("/basedir/sub/src.adoc")),
expected: Ok(FilePath("/basedir/sub/other.adoc".to_string())),
..TestCase::default()
},
TestCase {
name: "basic absolute include",
target_str: "/abs/other.adoc",
src_file: SourceFile::Path(Path::new("/path/to/src.adoc")),
expected: Ok(FilePath("/abs/other.adoc".to_string())),
..TestCase::default()
},
TestCase {
name: "relative canonicalized",
src_is_primary: false,
target_str: "../other.adoc",
src_file: SourceFile::Path(Path::new("/d1/d2/src.adoc")),
expected: Ok(FilePath("/d1/d2/../other.adoc".to_string())),
..TestCase::default()
},
];
for case in cases {
let actual = prepare(
case.target_str,
case.target_is_uri,
&case.src_file,
case.src_is_primary,
case.base_dir,
);
assert_eq!(actual, case.expected, "TestCase.name: {:?}", case.name);
}
}
}