assert-rs / assert_fs Goto Github PK
View Code? Open in Web Editor NEWFilesystem fixtures and assertions.
Home Page: docs.rs/assert_fs
License: Apache License 2.0
Filesystem fixtures and assertions.
Home Page: docs.rs/assert_fs
License: Apache License 2.0
The documentation for .into_persistent
(and .into_persistent_if
) suggest you can delete a persisted TempDir
by calling .close
on it.
Lines 120 to 129 in 9c5caf2
However, the implementation of .close
explicitly doesn't do anything when the TempDir
has been persisted.
Line 191 in 9c5caf2
So, either
TempDir
can't be deleted, or.close
should be updated to remove persisted
TempDir`.I ran into this while trying to work around #51 by trying to persist-by-default and close/delete on success.
Looking at https://docs.rs/assert_fs/0.3.0/assert_fs/, what should be imported to top-level and what shouldn't?
Examples
assert
contains details that aren't as relevant for most users and shouldn't be top-levelChildPath
references TempDir
but doesn't linkIntoPathPredicate
doesn't link to stuffhttps://docs.rs/assert_fs/1.0.1/assert_fs/assert/trait.PathAssert.html#required-methods says you can pass a &Path, but this errors with:
error[E0277]: the trait bound `&Path: IntoPathPredicate<_>` is not satisfied
--> src/git/tests.rs:54:36
|
54 | clone.child("HEAD").assert(repo.child("HEAD").path());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoPathPredicate<_>` is not implemented for `&Path`
In case someone wants custom temp dir functionality or some other unknown situation.
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!
A re-export of https://docs.rs/tempfile/3.0.4/tempfile/fn.tempfile.html should suffice to prevent a lot of people from adding tempfile as a dependency!
Also cf. https://gitter.im/rust-lang/WG-CLI?at=5bba1f933844923661fa9d79
Right now you have to hunt through all of the traits and it makes it hard to see the big picture.
Right now, str
gets turned into a Utf8<Difference>
set of predicates. Should we add trimming and line ending normalization to that?
assert_cli did trimming. This would allow people to work around it by directly passing in a predicate rather than relying on IntoOutputPredicate
. Related: assert-rs/assert_cli#77
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
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.
Here https://github.com/assert-rs/assert_fs/blob/master/LICENSE-MIT#L1 the copyright is assigned to the The assert_cli Developers, in 2015.
This might maybe be an error since the first commit is in 2018? Or is this package based on some work that they have done?
So far, we only have file system fixture initialization and not file system assertions
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.
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".
This will provide more useful panic information, by default
See https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1460-2020-08-27
Maintainer Edit: There are two problems that we became aware of in this issue
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);
}
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();
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
Areas to improve
Successes
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 usingassert_fs
.
Can I assert metadata of a file, like permissions, file type, access time, etc?
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.
Summary
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.
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!
So what if you programmatically create data and want to serialize it?
Should we have
write_yml(serde)
write_json(serde)
write_toml(serde)
Since its in our public interface, we are blocked on it for going to 1.0
See also assert-rs/predicates-rs#30
It'd be easier to throw this at things if it had AsRef<Path>
everywhere or something.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are awaiting their schedule. Click on a checkbox to get an update now.
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/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
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
.github/workflows/ci.yml
STABLE 1.80
STABLE 1.80
STABLE 1.80
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:
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).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());
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());
It isn't always clear what you can do.
The fixture logic uses a mix of error types. We should unify them.
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.)
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 :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.