Skip to content
This repository has been archived by the owner on Dec 29, 2021. It is now read-only.

Review/feedback #16

Merged
merged 10 commits into from
Mar 22, 2017
Merged

Review/feedback #16

merged 10 commits into from
Mar 22, 2017

Conversation

colin-kiegel
Copy link
Collaborator

@colin-kiegel colin-kiegel commented Mar 21, 2017

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

- make the header less cluttered
- add generic docs badge
- remove coveralls badge (its not up-to-date)
- print() -> prints()
- 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) {
Copy link
Collaborator Author

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;
Copy link
Collaborator Author

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. :-)

Copy link
Collaborator

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

  1. things from std
  2. things from external crates
  3. my things

and sort the individual blocks alphanumerically

Copy link
Collaborator Author

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>,
Copy link
Collaborator Author

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). :-)

Copy link
Collaborator

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.

Copy link
Collaborator Author

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. ;-)

Copy link
Collaborator

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`:
Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

Copy link
Collaborator

@killercup killercup left a 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]. :-)
Copy link
Collaborator

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

Copy link
Collaborator Author

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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/errors.rs Outdated
@@ -1,3 +1,5 @@
static ERROR_PREFIX: &'static str = "CLI assertion failed";
Copy link
Collaborator

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?

Copy link
Collaborator Author

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;
Copy link
Collaborator

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

  1. things from std
  2. things from external crates
  3. 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!
Copy link
Collaborator

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,
Copy link
Collaborator

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.

Copy link
Collaborator Author

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?

Copy link
Collaborator

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"),
}
}
}
Copy link
Collaborator

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 😄

Copy link
Collaborator Author

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>,
Copy link
Collaborator

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;
Copy link
Collaborator

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,
Copy link
Collaborator

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))

Copy link
Collaborator Author

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`:
Copy link
Collaborator

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.

@killercup
Copy link
Collaborator

@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.

@colin-kiegel
Copy link
Collaborator Author

@killercup I had all the todos ready and quite a bunch of documentation changes. But I stopped, because of the macro issue.

@colin-kiegel
Copy link
Collaborator Author

have you worked in parallel?

PS: seems that only clippy fails the travis build https://travis-ci.org/killercup/assert_cli/builds/214033920

@colin-kiegel
Copy link
Collaborator Author

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). :-)

@killercup
Copy link
Collaborator

(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.

@colin-kiegel
Copy link
Collaborator Author

ok :-)

@killercup
Copy link
Collaborator

Actually, wait, keep the macro changes in if it's any kind of hassle to pull them out. It's strictly better than before.

@colin-kiegel
Copy link
Collaborator Author

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?

@killercup
Copy link
Collaborator

killercup commented Mar 22, 2017

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.

@colin-kiegel
Copy link
Collaborator Author

btw. is the typo in non-exisiting-file intentional? I guess so. If not, I can correct it. :-)

@killercup
Copy link
Collaborator

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
@colin-kiegel
Copy link
Collaborator Author

ok done :-)

@killercup
Copy link
Collaborator

Very nice! Thanks for making these changes so quickly! Now, let's get this merged already!

… Oh Clippy, what now?

error: you should put `assert_cli` between ticks in the documentation
  --> src/macros.rs:74:76
   |
74 | /// information about whitespaces, to address https://github.com/killercup/assert_cli/issues/22.
   |                                                                            ^^^^^^^^^^
   |
   = note: #[deny(doc_markdown)] implied by #[deny(warnings)]

I'll make it a nice link and merge manually.

@killercup killercup merged commit e307b80 into assert-rs:master Mar 22, 2017
@killercup
Copy link
Collaborator

🎉

@colin-kiegel
Copy link
Collaborator Author

Thank you, too. I had a lot of fun. :-)

@colin-kiegel colin-kiegel deleted the review/feedback branch March 22, 2017 23:05
@killercup killercup mentioned this pull request Mar 22, 2017
3 tasks
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants