Skip to content
Merged
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
218 changes: 204 additions & 14 deletions src/assert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
//!
//! # Examples
//!
//! ```rust,ignore
//! use assert_fs::*;
//! ```rust
//! extern crate assert_fs;
//! extern crate predicates;
//!
//! use assert_fs::prelude::*;
//! use predicates::prelude::*;
//!
//! let temp = assert_fs::TempDir::new().unwrap();
Expand All @@ -31,14 +34,25 @@ use predicates::str::PredicateStrExt;
use predicates_core;
use predicates_tree::CaseTreeExt;

use fs;
use fixture;

/// Assert the state of files within [`TempDir`].
///
/// This uses [`IntoPathPredicate`] to provide short-hands for common cases, accepting:
/// - `Predicate<Path>` for validating a path.
/// - `Predicate<str>` for validating the content of the file.
/// - `&Path` which must have the same file content.
/// - `&[u8]` or `&str` representing the content of the file.
///
/// See [`predicates`] for more predicates.
///
/// # Examples
///
/// ```rust,ignore
/// use assert_fs::*;
/// ```rust
/// extern crate assert_fs;
/// extern crate predicates;
///
/// use assert_fs::prelude::*;
/// use predicates::prelude::*;
///
/// let temp = assert_fs::TempDir::new().unwrap();
Expand All @@ -53,21 +67,54 @@ use fs;
/// temp.close().unwrap();
/// ```
///
/// - See [`predicates::prelude`] for more predicates.
/// - See [`IntoPathPredicate`] for other built-in conversions.
///
/// [`TempDir`]: ../struct.TempDir.html
/// [`predicates::prelude`]: https://docs.rs/predicates/0.9.0/predicates/prelude/
/// [`predicates`]: https://docs.rs/predicates
/// [`IntoPathPredicate`]: trait.IntoPathPredicate.html
pub trait PathAssert {
/// Wrap with an interface for that provides assertions on the `TempDir`.
/// Assert the state of files within [`TempDir`].
///
/// This uses [`IntoPathPredicate`] to provide short-hands for common cases, accepting:
/// - `Predicate<Path>` for validating a path.
/// - `Predicate<str>` for validating the content of the file.
/// - `&Path` which must have the same file content.
/// - `&[u8]` or `&str` representing the content of the file.
///
/// See [`predicates`] for more predicates.
///
/// # Examples
///
/// ```rust
/// extern crate assert_fs;
/// extern crate predicates;
///
/// use assert_fs::prelude::*;
/// use predicates::prelude::*;
///
/// let temp = assert_fs::TempDir::new().unwrap();
/// let input_file = temp.child("foo.txt");
/// input_file.touch().unwrap();
///
/// // ... do something with input_file ...
///
/// input_file.assert("");
/// // or
/// input_file.assert(predicate::str::is_empty());
///
/// temp.child("bar.txt").assert(predicate::path::missing());
///
/// temp.close().unwrap();
/// ```
///
/// [`TempDir`]: ../struct.TempDir.html
/// [`predicates`]: https://docs.rs/predicates
/// [`IntoPathPredicate`]: trait.IntoPathPredicate.html
fn assert<I, P>(&self, pred: I) -> &Self
where
I: IntoPathPredicate<P>,
P: predicates_core::Predicate<path::Path>;
}

impl PathAssert for fs::TempDir {
impl PathAssert for fixture::TempDir {
fn assert<I, P>(&self, pred: I) -> &Self
where
I: IntoPathPredicate<P>,
Expand All @@ -78,7 +125,7 @@ impl PathAssert for fs::TempDir {
}
}

impl PathAssert for fs::ChildPath {
impl PathAssert for fixture::ChildPath {
fn assert<I, P>(&self, pred: I) -> &Self
where
I: IntoPathPredicate<P>,
Expand All @@ -102,6 +149,26 @@ where

/// Used by [`PathAssert`] to convert Self into the needed [`Predicate<Path>`].
///
/// # Examples
///
/// ```rust
/// extern crate assert_fs;
/// extern crate predicates;
///
/// use std::path;
///
/// use assert_fs::prelude::*;
/// use predicates::prelude::*;
///
/// let temp = assert_fs::TempDir::new().unwrap();
///
/// // ... do something with input_file ...
///
/// temp.child("bar.txt").assert(predicate::path::missing()); // Uses IntoPathPredicate
///
/// temp.close().unwrap();
/// ```
///
/// [`PathAssert`]: trait.PathAssert.html
/// [`Predicate<Path>`]: https://docs.rs/predicates-core/0.9.0/predicates_core/trait.Predicate.html
pub trait IntoPathPredicate<P>
Expand All @@ -127,7 +194,26 @@ where
}

// Keep `predicates` concrete Predicates out of our public API.
/// Predicate used by `IntoPathPredicate` for bytes
/// [Predicate] used by [`IntoPathPredicate`] for bytes.
///
/// # Example
///
/// ```rust
/// use assert_fs::prelude::*;
///
/// let temp = assert_fs::TempDir::new().unwrap();
/// let input_file = temp.child("foo.txt");
/// input_file.touch().unwrap();
///
/// // ... do something with input_file ...
///
/// input_file.assert(b"" as &[u8]); // uses BytesContentPathPredicate
///
/// temp.close().unwrap();
/// ```
///
/// [`IntoPathPredicate`]: trait.IntoPathPredicate.html
/// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html
#[derive(Debug)]
pub struct BytesContentPathPredicate(
predicates::path::FileContentPredicate<predicates::ord::EqPredicate<&'static [u8]>>,
Expand Down Expand Up @@ -174,7 +260,26 @@ impl IntoPathPredicate<BytesContentPathPredicate> for &'static [u8] {
}

// Keep `predicates` concrete Predicates out of our public API.
/// Predicate used by `IntoPathPredicate` for `str`
/// [Predicate] used by `IntoPathPredicate` for `str`.
///
/// # Example
///
/// ```rust
/// use assert_fs::prelude::*;
///
/// let temp = assert_fs::TempDir::new().unwrap();
/// let input_file = temp.child("foo.txt");
/// input_file.touch().unwrap();
///
/// // ... do something with input_file ...
///
/// input_file.assert(""); // Uses StrContentPathPredicate
///
/// temp.close().unwrap();
/// ```
///
/// [`IntoPathPredicate`]: trait.IntoPathPredicate.html
/// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html
#[derive(Debug, Clone)]
pub struct StrContentPathPredicate(
predicates::path::FileContentPredicate<
Expand Down Expand Up @@ -222,6 +327,91 @@ impl IntoPathPredicate<StrContentPathPredicate> for &'static str {
}
}

// Keep `predicates` concrete Predicates out of our public API.
/// [Predicate] used by `IntoPathPredicate` for `str` predicates.
///
/// # Example
///
/// ```rust
/// extern crate assert_fs;
/// extern crate predicates;
///
/// use assert_fs::prelude::*;
/// use predicates::prelude::*;
///
/// let temp = assert_fs::TempDir::new().unwrap();
/// let input_file = temp.child("foo.txt");
/// input_file.touch().unwrap();
///
/// // ... do something with input_file ...
///
/// input_file.assert(predicate::str::is_empty()); // Uses StrPathPredicate
///
/// temp.close().unwrap();
/// ```
///
/// [`IntoPathPredicate`]: trait.IntoPathPredicate.html
/// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html
#[derive(Debug, Clone)]
pub struct StrPathPredicate<P: predicates_core::Predicate<str>>(
predicates::path::FileContentPredicate<predicates::str::Utf8Predicate<P>>,
);

impl<P> StrPathPredicate<P>
where
P: predicates_core::Predicate<str>,
{
pub(crate) fn new(value: P) -> Self {
let pred = value.from_utf8().from_file_path();
StrPathPredicate(pred)
}
}

impl<P> predicates_core::reflection::PredicateReflection for StrPathPredicate<P>
where
P: predicates_core::Predicate<str>,
{
fn parameters<'a>(
&'a self,
) -> Box<Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> {
self.0.parameters()
}

/// Nested `Predicate`s of the current `Predicate`.
fn children<'a>(&'a self) -> Box<Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> {
self.0.children()
}
}

impl<P> predicates_core::Predicate<path::Path> for StrPathPredicate<P>
where
P: predicates_core::Predicate<str>,
{
fn eval(&self, item: &path::Path) -> bool {
self.0.eval(item)
}
}

impl<P> fmt::Display for StrPathPredicate<P>
where
P: predicates_core::Predicate<str>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}

impl<P> IntoPathPredicate<StrPathPredicate<P>> for P
where
P: predicates_core::Predicate<str>,
{
type Predicate = StrPathPredicate<P>;

fn into_path(self) -> Self::Predicate {
Self::Predicate::new(self)
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
Loading