diff --git a/README.md b/README.md index 5205003..e5dc156 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Provides injectable Filesystem and Network resources to make code more testable. #### std::fs alternatives -- [ ] `std::fs::canonicalize` - `path(path).canonicalize()` - Returns the canonical, absolute form of a path with all intermediate components normalized and symbolic links resolved. +- [x] `std::fs::canonicalize` - `path(path).canonicalize()` - Returns the canonical, absolute form of a path with all intermediate components normalized and symbolic links resolved. - [x] `std::fs::copy` - `file(path).copy(target)` - Copies the contents of one file to another. This function will also copy the permission bits of the original file to the destination file. - [x] `std::fs::create_dir` - `dir(path).create()` - Creates a new, empty directory at the provided path - [x] `std::fs::create_dir_all` - `dir(path).create_all()` - Recursively create a directory and all of its parent components if they are missing. diff --git a/src/fs/path.rs b/src/fs/path.rs index 9325971..58937ff 100644 --- a/src/fs/path.rs +++ b/src/fs/path.rs @@ -283,6 +283,25 @@ impl<'base, 'path, T: PathType> PathReal<'base, 'path, T> { self.check_error()?; Ok(self.as_pathbuf().is_symlink()) } + + /// Returns the canonical, absolute form of the path with all intermediate + /// components normalized and symbolic links resolved. + /// + /// ``` + /// # use kxio::fs::Result; + /// # fn main() -> Result<()> { + /// let fs = kxio::fs::temp()?; + /// let path = fs.base().join("foo"); + /// # fs.dir(&path).create()?; + /// let dir = fs.path(&path); + /// let canonical = dir.canonicalize()?; + /// # Ok(()) + /// # } + /// ``` + pub fn canonicalize(&self) -> Result { + self.check_error()?; + self.as_pathbuf().canonicalize().map_err(Error::Io) + } } impl<'base, 'path> From> for PathBuf { fn from(path: PathReal) -> Self { diff --git a/tests/fs.rs b/tests/fs.rs index 7d947de..cb2899d 100644 --- a/tests/fs.rs +++ b/tests/fs.rs @@ -661,3 +661,27 @@ mod dir { } } } +mod canonicalize { + use std::path::Path; + + use super::*; + + #[test] + fn should_resolve_symlinks() -> TestResult { + let fs = fs::temp().expect("temp fs"); + + let file_path = fs.base().join("foo"); + let file = fs.file(&file_path); + file.write("bar").expect("write"); + + let link_path = fs.base().join("link"); + let link = fs.path(&link_path); + file.soft_link(&link).expect("create"); + let canonical = link.canonicalize().expect("canonicalize"); + // macos puts all temp files under /private + let canonical = Path::new("/").join(canonical.strip_prefix("/private").unwrap()); + assert_eq!(canonical, file_path); + + Ok(()) + } +}