use std::borrow::Cow;
use std::env;
use std::fs::File;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use pathdiff;
#[must_use]
pub fn path_relative_to_cwd(path: &Path) -> Cow<Path> {
static CWD: OnceLock<Option<PathBuf>> = OnceLock::new();
let Some(base_dir) = CWD.get_or_init(|| {
#[cfg(test)]
{
return Some(PathBuf::from(env!("CARGO_MANIFEST_DIR")));
}
#[allow(unreachable_code)]
env::current_dir().ok()
}) else {
#[cfg(not(tarpaulin_include))]
return Cow::Borrowed(path);
};
if let Some(diffed) = pathdiff::diff_paths(path, base_dir) {
if diffed == Path::new("") {
Cow::Borrowed(path)
} else {
Cow::Owned(diffed)
}
} else {
Cow::Borrowed(path)
}
}
pub fn read_to_string_buffer(buffer: &mut String, path: &Path) -> io::Result<usize> {
let mut file = File::open(path)?;
buffer.clear();
file.read_to_string(buffer)
}
#[cfg(test)]
mod tests {
use super::*;
const CWD: &str = env!("CARGO_MANIFEST_DIR");
#[test]
fn path_relative_to_cwd_regular() {
let file = Path::new(CWD).join("foo/bar.txt");
assert_eq!(path_relative_to_cwd(&file), Path::new("foo/bar.txt"));
}
#[test]
fn path_relative_to_cwd_equal() {
let file = Path::new(CWD);
assert_eq!(path_relative_to_cwd(file), file);
}
#[test]
fn path_relative_to_cwd_parent() {
let file = Path::new(CWD).parent().unwrap().join("foo/bar.txt");
assert_eq!(path_relative_to_cwd(&file), Path::new("../foo/bar.txt"));
}
#[test]
fn path_relative_to_cwd_relative_path() {
let file = Path::new("foo/bar.txt");
assert_eq!(path_relative_to_cwd(file), file);
}
}