Coder Social home page Coder Social logo

assert_fs's Introduction

assert_fs

Assert Filesystems - Filesystem fixtures and assertions for testing.

Documentation License Crates Status

assert_fs aims to simplify

  • Setting up files for your tests to consume
  • Asserting on files produced by your tests

Example

Here is a trivial example:

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("");
temp.child("bar.txt").assert(predicate::path::missing());
temp.close().unwrap();

See the documentation for more information.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

assert_fs's People

Contributors

dependabot-preview[bot] avatar dependabot-support avatar epage avatar ignatenkobrain avatar killercup avatar peter-kehl avatar pidelport avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

assert_fs's Issues

Provide a `write_file()` method for `ChildPath`

What this would bring over using the existing copy_from() for a single file is the ability to copy the file to a different name. Basically I'd like the semantics of write_binary() and write_str() but using an existing file as source.

use assert_fs::prelude::*;

let temp = assert_fs::TempDir::new().unwrap();
temp
   .child("input.txt")
   .write_file("unittest.42.txt")
   .unwrap();
temp.close().unwrap();

The rationale is that my program uses fixed names for various input files (and/or I don't want to bother configuring my program to use other filenames), but I have many different input files for as many different unittests. I want to say "for this test, the content of input.txt will be taken from that example file".

What is needed for 1.0?

Collecting feedback or assert_fs. Please post even if you think it might not be needed for 1.0 so we can try to get the big picture of uses, challenges, etc. We're also looking at including experience reports in the 1.0 announcement blog post.

Preferably, please update to the latest version first but don't let upgrading stop you from providing feedback

To help spur feedback, consider these questions

  • Why do you use this crate?
  • Why don't you use it more?
  • How does this crate fit into your testing strategy?
  • Is there anything that feels out of place / not rust-like?
  • Are there common patterns you implement on top of this crate (e.g. fixture setup or assertions we don't support)?

Summary

Areas to improve

  • #47 Improve overview / introduction in README / docs.rs
  • #48 Call out in docs that you can operate on things besides the built-in temp support

Successes

@volks73

I use assert_fs because I wanted more elegant, shorter, and fluent-style tests. I liked how the crate appeared to make working with paths easier. I noticed a lot of my tests were just building paths to files and directories, which can be verbose and cumbersome in Rust. In an effort to reduce boilerplate and make my tests shorter and easier to follow, I started using assert_fs.

Improve overview / introduction in README / docs.rs

Summary

  • Give better overview of what this crate is and how it works
  • Do a better job explaining why this crate is better than hand-rolling a solution

From @passcod on #46

Going under the "Why don't you use this crate" category as linked from assert_cmd.

Foremost, while the rustdoc is good as a reference, the upfront documentation is severely lacking. The readme is practically useless both for figuring out what this is (beyond the title, which is only helpful if one knows what all the words mean), and figuring out what it can do (and hence, whether it can be used for one's usecase). Going to the docs.rs page in some hope of more is equally discouraging (and also non-obvious from github as it's only linked through the badge), as the crate top-level documentation is an extremely succinct "overview" that doesn't really explain anything.

Specifically, but not exhaustively, there's no obvious documentation for how this crate works (or how it doesn't work), for example whether it's just manipulating real files or offering a fake filesystem, whether it does any magic or introduces any behaviour we'd need to be careful around, that kinda thing. There's no explanation of what fixtures are or why they're useful, nor even a link to a discussion of that. There's also nothing that argues in favour of using this crate rather than rolling one's own testing code.

Running commands and dealing with output can be complex in many many ways, so assert_cmd smoothing that is excellent, very much welcome, and improves ergonomics significantly. File I/O is a lot more bread-and-butter and assert_fs doesn't feel, on the outset, as significant enough to add or rewrite in, especially when it's not obvious what it does, really.

into_persistent(_if) documentation confusion

The documentation for .into_persistent (and .into_persistent_if) suggest you can delete a persisted TempDir by calling .close on it.

/// ```no_run
/// use assert_fs::fixture::TempDir;
///
/// let tmp_dir = TempDir::new()
/// .unwrap()
/// .into_persistent();
///
/// // Ensure deletion happens.
/// tmp_dir.close().unwrap();
/// ```

However, the implementation of .close explicitly doesn't do anything when the TempDir has been persisted.

Inner::Persisted(_) => (),

So, either

  1. the documentation example should be updated to clarify a persisted TempDir can't be deleted, or
  2. the implementation of .close should be updated to remove persisted TempDir`.

Some background

I ran into this while trying to work around #51 by trying to persist-by-default and close/delete on success.

symlink verification fails for link -> file?

This is quite the edge case, but I've got a test configured where I perform filesystem operations using SFTP against the local machine connected to itself. In the screenshot below, the test connects the machine to itself and leverages SFTP to create a symlink to a file. The symlink is created successfully, but when testing the link using assert_fs, it seems to think it is a file and not a symlink (unless I'm reading it wrong). When pulling the file stat information via sftp, it is properly reflected as a symlink.

image

add methods to create subdirs

I've extended the ChildPath in my project in order to do that โ€” see glehmann/hld@00bc932#diff-475a9530a9c1e888d097445199b74c2fR402

pub trait TestPathChild {
    fn child<P>(&self, path: P) -> assert_fs::fixture::ChildPath
    where
        P: AsRef<std::path::Path>;
    fn mkdir_all(&self) -> std::io::Result<()>;
}

impl TestPathChild for assert_fs::fixture::ChildPath {
    fn child<P>(&self, path: P) -> assert_fs::fixture::ChildPath
    where
        P: AsRef<std::path::Path>,
    {
        assert_fs::fixture::ChildPath::new(self.path().join(path))
    }
    fn mkdir_all(&self) -> std::io::Result<()> {
        std::fs::create_dir_all(self.path())
    }
}

used this way:

let tmp = assert_fs::TempDir::new().unwrap();
let subdir = tmp.child("hop").child("hop").child("hop");
let foo = subdir.child("foo.txt");
subdir.mkdir_all().unwrap();
foo.write_str(&lorem_ipsum).unwrap();

It might be good to support this feature natively :)

Symlink support?

This is platform specific as it only is for unix, but is there any consideration on supporting symlinks for child paths where you have something like

let temp = assert_fs::TempDir::new().unwrap();

// Make a real file
let file = temp.child("file");
file.touch().unwrap();

// Make a symlink to a file (only available on unix platform)
temp.child("link").link(file).unwrap();

Add conversion from tempfile::TempDir to assert_fs::TempDir

As mentioned and requested in #48, sometimes it might be necessary or needed to customize the temporary directory generated during tests. For example, the tempfile crate provides the tempfile::Builder type for customizing the temporary directory. Similar customizations are not possible with the assert_fs::TempDir.

As a way to avoid re-implementation of the tempfile::Builder customizations, a From implementation could be added to the assert_fs::TempDir type. Two separate From implementations could be added: (1) tempfile::TempDir and (2) tempfile::Builder. This would allow for the following:

let ex_temp_dir_1 = assert_fs::TempDir::from(tempfile::Builder::new().prefix("hello-world-").build());
// and/or
let ex_temp_dir_2 = assert_fs::TempDir::from(tempfile::Builder::new().prefix("hello-world-again-"));

This also means the complementary Into implementations would also exist.

I do recognize the majority use-case is to just create a "default" temporary directory, but this would add some functionality and flexibility for more uncommon test cases without having to re-implement anything.

Document that assert panics

It's non-obvious that assert panics, even if it's what one would expect it does.

(Side-note: a non-panicking, "check" function, that returns a Result which can be unwrapped, could be useful to have. But just documenting the panic behaviour of assert would also work.)

impl AsRef for *

It'd be easier to throw this at things if it had AsRef<Path> everywhere or something.

Bugs in documentation

  • Not sure if you have/want warn on missing docs, too?
  • Not sure everyone understands what's the implications of "scratchpad", so maybe make it explicit? random name, gets cleaned up when it leaves scope.
  • ChildPath references TempDir but doesn't link
  • Links to predicates::prelude are broken
  • IntoPathPredicate doesn't link to stuff

show diff (or at least actual content) for failed file content assertions

testdir.child("file").assert("content");

with an assertion like this, if the content of file is something other than content, I would expect to be shown a diff, or maybe expected/actual for comparison. actual output looks like this:

thread 'tests::test' panicked at 'Unexpected file, failed 

path="/tmp/.tmpGJaDlM/file"', .../github.com-1ecc6299db9ec823/assert_fs-0.10.0/src/assert.rs:146:9

This is otherwise a very helpful library, thank you for your work!

TempDir: Provide an API to not delete-dir-on-drop without consuming the TempDir

The current API offers into_path(self) -> PathBuf which is nice and clean (not sure why PathBuf instead of Path, but I can live with that), but forces you to decide ahead of time if you want a temporary or persisted path.

I'd like to change the behaviour at runtime, but am hitting the following snags:

  • If I call into_path() near the end of my scope, it might not get called because of asserts that triggered earlyer (precisely when I'd have liked to keep the tempdir).
  • If I call it at the beginning of my scope, I either run into PathBuf/TempDir type mismatches, or into temporary value does not live long enough problems:
let tempdir = TempDir::new().unwrap();
// Doesn't compile because of lifetime issues
let cwd = match std::env::var("ASSERTFS_KEEP_TEMP") {
    Ok(_) => tempdir.into_path().as_path(),
    Err(_) => tempdir.path(),
};
assert!(dostuff(cwd).is_ok());
// Too late: assert has fired already.
if std::env::var("ASSERTFS_KEEP_TEMP").is_ok() {
    tempdir.into_path();
}

Perhaps I missed an easy solution, but I doubt it would be as easy as having some kind of delete_on_drop(bool) API:

let tempdir = TempDir::new()
                      .unwrap()
                      .delete_on_drop(std::env::var("ASSERTFS_KEEP_TEMP").is_ok());
assert!(dostuff(cwd).is_ok());

Workaround

let tempdir = TempDir::new().unwrap();
let mut cwd = PathBuf::new();
match env::var("ASSERTFS_KEEP_TEMP") {
    Ok(_) => cwd.push(&tempdir.into_path()),
    Err(_) => cwd.push(tempdir.path()),
}
assert!(dostuff(cwd).is_ok());

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Repository problems

These problems occurred while renovating this repository. View logs.

  • WARN: Use matchDepNames instead of matchPackageNames

This repository currently has no open or pending branches.

Detected dependencies

cargo
Cargo.toml
  • tempfile 3.0
  • globwalk 0.9
  • predicates 3.0.1
  • predicates-core 1.0.6
  • predicates-tree 1.0.1
  • doc-comment 0.3
  • anstyle 1.0.0
  • anstream 0.6.7
  • automod 1.0.14
github-actions
.github/workflows/audit.yml
  • actions/checkout v4
  • actions-rs/audit-check v1
  • actions/checkout v4
  • EmbarkStudios/cargo-deny-action v1
.github/workflows/ci.yml
  • actions/checkout v4
  • Swatinem/rust-cache v2
  • actions/checkout v4
  • Swatinem/rust-cache v2
  • actions/checkout v4
  • Swatinem/rust-cache v2
  • actions/checkout v4
  • Swatinem/rust-cache v2
  • actions/checkout v4
  • Swatinem/rust-cache v2
  • actions/checkout v4
  • Swatinem/rust-cache v2
  • github/codeql-action v3
  • actions/checkout v4
  • Swatinem/rust-cache v2
.github/workflows/committed.yml
  • actions/checkout v4
.github/workflows/pre-commit.yml
  • actions/checkout v4
  • actions/setup-python v5
  • pre-commit/action v3.0.1
.github/workflows/rust-next.yml
  • actions/checkout v4
  • Swatinem/rust-cache v2
  • actions/checkout v4
  • Swatinem/rust-cache v2
.github/workflows/spelling.yml
  • actions/checkout v4
regex
.github/workflows/ci.yml
  • STABLE 1.79
  • STABLE 1.79
  • STABLE 1.79

  • Check this box to trigger a request for Renovate to run again on this repository

Support workflow for persisting on panic

Maintainer Edit: There are two problems that we became aware of in this issue

  • Confusion over function names which was addressed by #56
  • Wanting to support a workflow that auto-persists on panic which is still not resolved and this issue is focused on.

There are trade offs though. If someone is unaware, it could really eat up their disk space, for example.

Original title: TempDir::persist_if(false) should make sure that TempDir is not persisted.

Original body:


Currently, persist_if(false) returns immediately, assuming that the TempDir was not persistent to begin with and that nothing needs to be done. This doesn't work if persist_if(true) had been called earlier.

I'd expect an API that takes a bool to allow switching between two states, but this one can only switch from false to true.

Use-case: I'd like to automatically persist files for failed tests only, so that I can debug failures without bloating my disk. A simple way to do this would be to persist_if(true) at the start and persist_if(false) after asserts have passed:

#[test]
fn foo() {
    let td = TempDir::new().unwrap().persist_if(true);
    assert!(write_files_and_return_true(&td));
    td.persist_if(false);
}

Call out in docs that you can operate on things besides the built-in temp support

In case someone wants custom temp dir functionality or some other unknown situation.

From @volks73 at #46

I would use assert_fs more if I could upgrade from v0.9. The assert_fs crate wraps the tempfile crate, but does not expose all of the functionality. For example, I need to be able to define a prefix for a temporary directory. The default .tmp prefix is an invalid name for a Cargo package. Windows is also not too keen on file and folder names with leading periods. This means I need to use the tempfile::Builder type to add a custom prefix. There is no Fromtempfile::TempDir trait implementation for assert_fs::TempDir, so I cannot use the tempfile::Builder type to customize a temporary directory and then "cast" it to the assert_fs::TempDir type to gain the assertion-ness and conveniences from the assert_fs crate, nor is there a similar Builder interface available. Thus, I am stuck using v0.9 of assert_fs, which does not wrap tempfile and instead just extends it.

This can be worked around today with ChildPath but the docs never talk about it!

Remove `failure` from the API

In the path to 1.0, I don't trust failure's API to not change. Therefore we should simplify so we minimize breaking changes.

Implement Debug for TempDir

Hi there,

I'm new to rust so this might be a stupid question, but why isn't there an implementation of Debug for TempDir? Is there a specific reason or it simply wasn't needed yet?

If there's no counter reason, I'd be glad to propose a pull request

Otherwise, I'd be glad if you could provide some rational

Looking forward to reading you

Jaffa

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.