-
Notifications
You must be signed in to change notification settings - Fork 21
Conversation
- note: std has `.` at the end of one-line doc-strings.
- try to mimic `assert_eq!` - close #14: try to avoid multiline panics
.. just a suggestion, since stdout and stderr are somewhat redundant.
src/errors.rs
Outdated
@@ -26,40 +26,23 @@ error_chain! { | |||
got, | |||
) | |||
} | |||
OutputMismatch(cmd: Vec<String>, expected: String, got: String) { | |||
OutputMismatch(output_name: String, cmd: Vec<String>, expected: String, got: String) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also embed the OutputType
enum directly - but then it must be public and would appear in the docs.
src/lib.rs
Outdated
@@ -65,7 +76,8 @@ | |||
extern crate difference; | |||
#[macro_use] extern crate error_chain; | |||
|
|||
use std::process::Command; | |||
use std::process::{Command, Output}; | |||
use std::fmt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any style recommendations how to order use and mod statements?
I regularly have this question - I don't know of any answer. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I think about it, I do it like
- things from std
- things from external crates
- my things
and sort the individual blocks alphanumerically
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, that sounds good. But when pub
and mod
come into play I find it less clear - I usually end up with
use std
use external
pub use mystuff
use myotherstuff
pub mod mymod
mod myothermod
But I've also seen mod use
mixed like here.
#[derive(Debug)] | ||
pub struct Assert { | ||
cmd: Vec<String>, | ||
expect_success: bool, | ||
expect_success: Option<bool>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Option<bool>
is more expressive than bool
. Because None
is the I-don't-care-case (e.g. should print "foo", but may fail or succeed).
If you don't like this change I'd suggest to change the docs instead. The call .succeeds()
is really all over the place and could then be omitted in almost all cases except the doc-comment for .succeeds()
itself, where it should state that this is pure decoration (unless you receive a partial assertion builder from somewhere). :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're right, this should be much more explicit. I'm also not sure if "expect success" is a good default, but I think I want to keep it for now. What do you think? Will the most common use case be to check something failed in a certain or that it succeeded?
I'm a big fan of fluent APIs and being explicit, that's why I added .succeeds()
everywhere in the docs (and added .and()
). It might be a good idea to leave it out in a few places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that succeeds
is a reasonable default and symmetry is not always the best design. But
- you would then need an un-setter
.fails_or_succeeds()
to express the I-don't-care-case - it should be well-documented
People may have very different expectations about this. So either way there might be confusion about the behaviour if it's not well-documented.
That could also be a candidate for a poll in users.rust-lang.org. ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #23 but have no immediate plans to implement it
If you want to check for the program's output, you can use `print` or | ||
`print_exactly`: | ||
If you want to match the program's output _exactly_, you can use | ||
`prints_exactly`: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a random comment.
When first poking around with this crate I found the semantics of prints
a bit surprising. I expected a strict equality assertion. Then I learned that there is prints_exactly
.
It's very likely a matter of taste and I might even change my mind (I often do), but I think I would prefer the strict assertion over the fuzzy assertion. I tried hard to think of a different naming, where the strict variant would have the shorter name, but I couldn't find something nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried hard to think of a different naming, where the strict variant would have the shorter name, but I couldn't find something nice.
Me neither! That's one of the main reason I made the exact method's name longer.
The previous version only had exact matching, and it was difficult to get right, because you had to include every new line (Maybe with carriage return on Windows? Who knows!) and control character.
This reminds of of another thing I want to support: Multiple fuzzy checks. I'll open an issue for that in a minute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, Colin, thank you so much, this is awesome! I chose to mark this as Comment instead of Approve as I left, well, a gazillion inline comments 😆
README.md
Outdated
|
||
```diff | ||
-1337 | ||
+92 | ||
``` | ||
|
||
More detailed information is available in the [documentation]. :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This link doesnt work because the link ref definition starts with an uppercase D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it's in the markdown specs, but github and my atom IDEs markdown preview treat it case-insensitive:
https://github.com/colin-kiegel/assert_cli/blob/1f29f4f25978bedf0bf476f5a27bedb0ea6a83e5/README.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, you win: http://spec.commonmark.org/0.27/#example-167
src/errors.rs
Outdated
@@ -1,3 +1,5 @@ | |||
static ERROR_PREFIX: &'static str = "CLI assertion failed"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Why static and not const?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I tend to forget that there are consts too. ^^
I'll link it in a todo list, at the top comment. :-)
src/lib.rs
Outdated
@@ -65,7 +76,8 @@ | |||
extern crate difference; | |||
#[macro_use] extern crate error_chain; | |||
|
|||
use std::process::Command; | |||
use std::process::{Command, Output}; | |||
use std::fmt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I think about it, I do it like
- things from std
- things from external crates
- my things
and sort the individual blocks alphanumerically
src/lib.rs
Outdated
//! (Make sure to include the crate as `#[macro_use] extern crate assert_cli;`!) | ||
//! Don't forget to import the crate with `#[macro_use]`. ;-) | ||
//! | ||
//! ## Don't Panic! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
#[derive(Debug)] | ||
struct OutputAssertion { | ||
expect: String, | ||
fuzzy: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the way you split out this struct, it's very neat.
Seeing how the code below with the matches on fuzziness etc. is pretty much duplicated, I'm wondering if maybe it can become a method on this type, like OutputAssertion::compare_with(String)
? (It might also be a good idea to make this struct generic over a trait OutputType
, but more on that in a comment below.)
At one point I was thinking about introducing an enum Precision { Exact, Fuzzy }
instead of using a bool, but didn't go through with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we start a separate discussion about future refactoring, e.g. in the ticket #20 you created, or yet another general architecture discussion ticket?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I think I'll just open a new PR where I try that design after this one gets merged. Issues that are not about bugs or features but contain a ton of quoted code are kinda hard to keep track of :)
src/lib.rs
Outdated
OutputType::StdErr => write!(f, "stderr"), | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing this – an enum with two impl blocks – we could also use two unit structs and introduce a trait OutputType
which both implement, that requires a Display impl and has a select(&Output) -> &[u8]
method.
This way (as alluded to above) we can add a field kind: T
to what is then OutputAssertion<T>
and change the last two fields in Assert
to Option<OutputAssertion<Stdout>>
and Option<OutputAssertion<Stderr>>
respectively.
I'm not sure this is a truly nicer design; I got the idea from wanting to encapsulate the whole output comparison business. Maybe it's totally over engineered 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I generally tend to prefer traits too. Hm, maybe we keep that idea in mind for the 'general architecture' discussion?
#[derive(Debug)] | ||
pub struct Assert { | ||
cmd: Vec<String>, | ||
expect_success: bool, | ||
expect_success: Option<bool>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're right, this should be much more explicit. I'm also not sure if "expect success" is a good default, but I think I want to keep it for now. What do you think? Will the most common use case be to check something failed in a certain or that it succeeded?
I'm a big fan of fluent APIs and being explicit, that's why I added .succeeds()
everywhere in the docs (and added .and()
). It might be a good idea to leave it out in a few places.
@@ -228,7 +226,8 @@ impl Assert { | |||
/// .unwrap(); | |||
/// ``` | |||
pub fn succeeds(mut self) -> Self { | |||
self.expect_success = true; | |||
self.expect_exit_code = None; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
src/lib.rs
Outdated
@@ -134,7 +134,7 @@ impl std::default::Default for Assert { | |||
Assert { | |||
cmd: vec!["cargo", "run", "--"] | |||
.into_iter().map(String::from).collect(), | |||
expect_success: true, | |||
expect_success: None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to keep the "expect success", this is the only line that needs to change. (To Some(true)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes and that would fix a documentation bug, I introduced. I wrote everywhere /// Defaults to asserting _successful_ execution.
^^
Adding it to the todo list.
If you want to check for the program's output, you can use `print` or | ||
`print_exactly`: | ||
If you want to match the program's output _exactly_, you can use | ||
`prints_exactly`: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried hard to think of a different naming, where the strict variant would have the shorter name, but I couldn't find something nice.
Me neither! That's one of the main reason I made the exact method's name longer.
The previous version only had exact matching, and it was difficult to get right, because you had to include every new line (Maybe with carriage return on Windows? Who knows!) and control character.
This reminds of of another thing I want to support: Multiple fuzzy checks. I'll open an issue for that in a minute.
@colin-kiegel, I'll merge this with two additional commits, to use const, and to, for now, default to success. Ohh, as I was writing this, I saw your macro refactor commit 😅 I'll not include that commit for now, before deciding what I really want to do here (see #22 (comment)). This probably means Github will not mark this as merged. |
@killercup I had all the todos ready and quite a bunch of documentation changes. But I stopped, because of the macro issue. |
have you worked in parallel? PS: seems that only clippy fails the travis build https://travis-ci.org/killercup/assert_cli/builds/214033920 |
PPS: If you give me just a couple of minutes, then I will add the final commit closing the todos (except for the unsetter idea). :-) |
(Re CI: Clippy seems to have a cache/rustup problem) Sorry, didn't know you were working on this at this moment! Can you make a new PR for the macro, but the other commits here? I have no problem force-pushing master. |
ok :-) |
Actually, wait, keep the macro changes in if it's any kind of hassle to pull them out. It's strictly better than before. |
ok, that's what I was thinking. :-) I'll split my next commits in two parts - the todos above and some doc changes I'd like to suggest, ok? |
Sounds good. I'll probably merge all of them right aways 😄 PS: I set master to a commit right before my merge and added another commit on top for travis. I hope it's not too confusing. |
btw. is the typo in |
Haha, that was not on purpose, no :D And like all good typos it got copypasted all over the place! Feel free to correct it |
- explain asserting the exit codes - better reflect the fact that `success` is expected by default - tip/hint about the macro limitation
ok done :-) |
Very nice! Thanks for making these changes so quickly! Now, let's get this merged already! … Oh Clippy, what now?
I'll make it a nice link and merge manually. |
🎉 |
Thank you, too. I had a lot of fun. :-) |
Ok, here is my feedback. I bundled it into different topics, so it is easier for you to opt-out of individual suggestions. :-)
The later commits are those which might be more controversial. Only the last two change the API surface.
I'll leave further comments here and there. :-)
TODO