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

Add with_env helper #46

Merged
merged 1 commit into from
Oct 12, 2017
Merged

Add with_env helper #46

merged 1 commit into from
Oct 12, 2017

Conversation

Freyskeyd
Copy link
Contributor

Check the discussion in #27

Signed-off-by: Freyskeyd [email protected]

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.

Very cool! Thank you so much for this!

I left some inline comments. Most importantly, please move the tests so they become unit tests.

Also, I saw you merged master into this. That's fine; please keep on adding commits to this branch without rebasing, but it'd be awesome if you could squash it once all reviews are done :)

src/assert.rs Outdated
@@ -24,6 +26,7 @@ impl default::Default for Assert {
Assert {
cmd: vec!["cargo", "run", "--"]
.into_iter().map(String::from).collect(),
env: Environment::empty(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it should default to inherit.

pub vars: Vec<(String, String)>,
/// Define if the structure must inherit
pub inherit: bool,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

The fields should not be pub. The compile method's output is all we should ever test in integration tests.


/// Compile Environment object
pub fn compile(&self) -> Vec<(String, String)> {
::std::env::vars().chain(self.vars.clone()).collect()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this have an if self.inherit?

src/assert.rs Outdated
let command = command.args(&args);
let command = command
.env_clear()
.envs(::std::env::vars().chain(self.env.clone().vars))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm pretty sure you want to call compile here.

@@ -0,0 +1,72 @@
extern crate assert_cli;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you move all the tests into a #[cfg(test)] mod test in environment.rs and use the real with_env?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The fact is, with_env doesn't allow to test the environment object after ...

fn to_environment_tuple(&self) -> (String, String);
}

impl<'s, T: ToString, Z:ToString> EnvironmentItem for &'s (T, Z) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

space after Z:

src/assert.rs Outdated
/// .stdout().contains("TEST_ENV=OK")
/// .execute()
/// .unwrap();
/// ```
Copy link
Collaborator

Choose a reason for hiding this comment

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

Feel free to add some more examples here as they are the real integration tests :)

Copy link
Collaborator

@epage epage left a comment

Choose a reason for hiding this comment

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

I'm really liking this API!

.stderr(Stdio::piped());
let command = command.args(&args);
.stderr(Stdio::piped())
.env_clear()
Copy link
Collaborator

Choose a reason for hiding this comment

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

There a reason we unconditionally clear and then re-add the vars we cleared via compile?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In fact we need the env_clear() because .envs doesn't clear it or replace the whole variables.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I'm missing something. I had assumed we'd only call env_clear() when inherit == false. Its unclear to me why we need env_clear when inherit == true.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

By clearing the environment before adding our own environment, we don't have to check if inherit is true nor false in execute command. We just want to clear and add the appropriate environment. That's the environment role to know when to add the existing env or not.

If inherit is set to true, the compile method will return a merge of actual environment (env::vars()) and our customized variables. I think it's nicer to have a compile method returning what our environment will look like. But feel free to propose something else I'm ok with it :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

tl;dr move along, these aren't the droids you're looking for.

I think it's nicer to have a compile method returning what our environment will look like.

That is nice. It helps with testing, etc.

I just assumed that Assert would directly access the members of Environment and there wouldn't be a need for a public .compile().

Recreating an inherited environment is more work but I'm assuming it doesn't matter in this case, despite it being against "you pay for what you use" (adds cost to people not using these new features).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@killercup how do you see this test?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Set an env var to something that is not UTF-8. How would I get a byte slice like that? head -c 42 /dev/urandom | rcat --quote (with this rcat) gives me:

b"\xf4\xa9\xd5\x8d\xc0\xe8\x00\xff\x1dqz\x86k\x83\xcb~\xc1\x18!\xfa\x01J\x1c\\:\x18)%\xd4\xa6^7\xb4\x93\x80.\x9a\x9c\xe1\xcf\xe2,"

which is not valid UTF-8.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but vars() use UTF-8 variables, do we really want to support not valid UTF-8? I don't think..

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's exactly what I'm saying: I'm fine with only allowing our users to add UTF-8 vars but we should not destroy valid, inherited env vars. So, calling vars at all is probably not a good call, and vars_os is the better option. Btw, you can find the impl of how std::process::Command deals with env vars on Unix here (it uses a HashMap<OsString, (usize, CString)> to store env vars).

How much work would it be to allow OsStr instead of String in our APIs?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you still add a test with the non-UTF-8 env var value?

src/assert.rs Outdated
let command = command.args(&args);
.stderr(Stdio::piped())
.env_clear()
.envs(self.env.clone().compile()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function consumes Asssert so we should be able to avoid the .clone()

src/assert.rs Outdated
@@ -26,6 +29,7 @@ impl default::Default for Assert {
Assert {
cmd: vec!["cargo", "run", "--"]
.into_iter().map(String::from).collect(),
env: Environment::empty(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should the default be

  • empty
  • inherit (I presume this is std::process::Command's default and the current behavior)
  • None (use std::process::Command's default which is the current behavior)

/// Customized environment variables
pub vars: Vec<(String, String)>,
/// Define if the structure must inherit
pub inherit: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

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

}

impl Environment {
/// Create a new Environment object with inherit
Copy link
Collaborator

Choose a reason for hiding this comment

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

I feel like a little more context would be helpful
Create a new Environment that inherits this process' environment.

}
}

/// Create a new Environment object without inheriting
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same about more context. Also, it can be confusing to describe something by what it is not.

So maybe Create a new Environment independent of the current process's Environment?

src/assert.rs Outdated
@@ -3,14 +3,17 @@ use std::process::{Command, Stdio};
use std::path::PathBuf;
use std::vec::Vec;
use std::io::Write;
use std::convert::Into;
Copy link
Collaborator

Choose a reason for hiding this comment

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

That's in the prelude


fn command() -> Assert {
Assert::command(&["printenv"])
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

That's very clever 👍

Can you add an empty line below the fn?

#[cfg(test)]
mod test {
use super::*;
use super::super::Assert;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know it's a very good Assert, but use ::Assert; should suffice ;)

@Freyskeyd Freyskeyd force-pushed the master branch 2 times, most recently from f3b6e26 to 82288e6 Compare October 9, 2017 15:40
if self.inherit {
::std::env::vars().chain(self.vars.clone()).collect()
} else {
self.vars.clone()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should Environment be moved into this?

This would give the caller control on whether the .clone()s are needed or not. In our case, we call compile when consuming Assert, so we wouldn't need to call any of these .clone()s.

.travis.yml Outdated
@@ -5,13 +5,6 @@ rust:
- beta
- stable
- nightly
matrix:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@killercup @epage I removed the nightly-2017-03-15, are you ok with this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

How come?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The .envs methods from Command is stable since 1.10. But not for the 2017-03-15 build. I was wondering about why we are still testing this particular build.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The reason (which I like and want to copy to my other projects) is to pin the version of rust/clippy.

In my other projects, we are always running the latest clippy. Sometimes it is out of sync with rustc, so the build ignores clippy, losing coverage. Even when it succeeds, there might be new clippy warnings which will get turned into errors, sporadically breaking our build.

What I'd recommend is to lock us to a new version of clippy. This might be best as a separate PR so any clippy fixes don't get mixed in with your changes.

Copy link
Collaborator

@killercup killercup Oct 9, 2017

Choose a reason for hiding this comment

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

I'm a sucker for lints, clippy needs to stay! Hell, I might even enforce rustfmt!

What I'd recommend is to lock us to a new version of clippy. This might be best as a separate PR so any clippy fixes don't get mixed in with your changes.

I'll just do that in minute, @Freyskeyd you can merge in master after this.

Update: #47

Copy link
Collaborator

Choose a reason for hiding this comment

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

@killercup I love having everything checked in the CI!

I'm unsure how stable rustfmt's output is from release to release. I've not yet submitted a rustfmt.toml to my other projects. I have played with a build optimization for rustfmt for locking to a specific version that you might find handy.

See https://github.com/cobalt-org/cobalt.rs/blob/master/.travis.yml#L29

Copy link
Collaborator

Choose a reason for hiding this comment

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

You're using the old rustfmt, not rustfmt-nightly :) I opened #48 for getting our formatting in check.

@Freyskeyd
Copy link
Contributor Author

@killercup can you check why the CI doesn't pass?

@killercup
Copy link
Collaborator

Probably because I tried being too clever… can you append || true to the travis.yml lines with the cargo install calls? 😅

@Freyskeyd Freyskeyd force-pushed the master branch 2 times, most recently from 588998b to 8cb7289 Compare October 10, 2017 12:17
@epage
Copy link
Collaborator

epage commented Oct 10, 2017

The command "[[ "$(cargo +nightly-2017-10-09 fmt -- --version)" != "$RUSTFMT_VERS"* ]] && \
  cargo +nightly-2017-10-09 install rustfmt-nightly --vers "$RUSTFMT_VERS" --force
  " failed and exited with 1 during .

https://travis-ci.org/killercup/assert_cli/builds/285971508

Probably because I tried being too clever… can you append || true to the travis.yml lines with the cargo install calls? 😅

I assume the || true is needed when the version check fails (its already installed), causing us not to reinstall the tool?

@killercup
Copy link
Collaborator

@Freyskeyd, wow, thanks for the quick OsString update!

@epage, yeah, it's a ternary: [[ if ]] && then || else. Which evals to a non-zero exit code without the else branch 😅

@epage
Copy link
Collaborator

epage commented Oct 10, 2017

@epage, yeah, it's a ternary: [[ if ]] && then || else. Which evals to a non-zero exit code without the else branch 😅

Would that cause the return value of then to be ignored?

@Freyskeyd
Copy link
Contributor Author

@killercup I tried with OsStr but it's a bit tricky. OsString is more easy and has the same type as vars_os().

About travis, what do you want to do?

@killercup
Copy link
Collaborator

Would that cause the return value of then to be ignored?

Maybe? Probably. We could also try to use a real if. Tbh, I'm fine with dealing with this later…

OsString is more easy and has the same type as vars_os().

Yes, sorry, I meant OsString!

About travis, what do you want to do?

Eh, I want you to fix the valid error and the formatting? 😛

@Freyskeyd Freyskeyd force-pushed the master branch 5 times, most recently from 3a528a9 to 835a843 Compare October 12, 2017 09:53
@Freyskeyd
Copy link
Contributor Author

@killercup @epage I updated the code, can you check it please? :)

@Freyskeyd
Copy link
Contributor Author

I move it to another crate because I need it outside assert_cli.

https://github.com/Freyskeyd/environment
https://crates.io/crates/environment

@epage epage mentioned this pull request Oct 12, 2017
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.

Awesome work. Having this as an external crate is pretty cool. Feel free to advertise that assert_cli uses it in its Readme ;)

Just a few more tiny nits and I will happily merge this :)

.stderr(Stdio::piped());
let command = command.args(&args);
.stderr(Stdio::piped())
.env_clear()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you still add a test with the non-UTF-8 env var value?

src/lib.rs Outdated
@@ -135,3 +137,4 @@ mod diff;
mod assert;
pub use assert::Assert;
pub use assert::OutputAssertionBuilder;
pub use environment::Environment;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you want to add some specific docs here mentioning this is a report from the external crate? I assume it inherits the docs from the item in the crate right now.

src/assert.rs Outdated
fn in_place_mod2() {
let x = Environment::inherit();

assert!(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why the assert!(… .is_ok()) dance when you can just write .unwrap()?

src/assert.rs Outdated
/// .stdout().is("FOO=BAR")
/// .execute()
/// .unwrap();
/// ```
Copy link
Collaborator

Choose a reason for hiding this comment

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

Great examples! Can you maybe add a third one that sets a var in the test's thread context and then shows that it's also available in the command output?

@Freyskeyd Freyskeyd force-pushed the master branch 2 times, most recently from 34fb40b to 16aaa61 Compare October 12, 2017 17:39
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.

Thanks for the updates!

Use Environment crate to override and insert new environment variables.

Signed-off-by: Freyskeyd <[email protected]>
@killercup
Copy link
Collaborator

bors r+

bors bot added a commit that referenced this pull request Oct 12, 2017
46: Add with_env helper r=killercup a=Freyskeyd

Check the discussion in #27 

Signed-off-by: Freyskeyd <[email protected]>
@bors
Copy link
Contributor

bors bot commented Oct 12, 2017

Build succeeded

@bors bors bot merged commit 060a7c0 into assert-rs:master Oct 12, 2017
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.

3 participants