Skip to content

Conversation

@vanstee
Copy link
Contributor

@vanstee vanstee commented Dec 1, 2013

  • ExUnit.configure
    • Made the assumption that you would never have a tag with a value of nil. Let me know if we need to allow it.
  • Tags support
    • Do we need any kind of option for running everything of the tests if all tests are filtered?
    • Testing this was pretty weird. Any thoughts on a better way to keep track of all passed/skipped tests compared to defining a custom formatter?
  • Mix support
    • Any thoughts on adding support for exclusion with a ~ prefix similar to rspec? Might be nice to just use the tag name combined with the exclusion for true and false (win32 or ~unix). Then everything else could be a string by default instead of needing a --filter os:unix: style filter.
    • Now all command line options are passed to ExUnit.configure after the test_helper.exs is run. Any scenarios where that would be a problem?

Closes #1898

Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need to store them, since we use it only on boot. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh good call. We can just print them straight from init/1.

@josevalim
Copy link
Member

Made the assumption that you would never have a tag with a value of nil. Let me know if we need to allow it.

Yeah, let's not make this assumption. Let's check explicitly with Keyword.has_key?/2!

Testing this was pretty weird. Any thoughts on a better way to keep track of all passed/skipped tests compared to defining a custom formatter?

The way you tackled this was actually pretty good. That's pretty much how we have to do it now.

Any thoughts on adding support for exclusion with a ~ prefix similar to rspec?

I think this is a good idea. Go for it!

Now all command line options are passed to ExUnit.configure after the test_helper.exs is run. Any scenarios where that would be a problem?

No, this is actually how it was supposed to work. :)

I have added some comments as well, this is looking really good! Thanks!

@krestenkrab
Copy link
Contributor

Would this fit my use case for Erjang? I'd like to be able to disable/enable specific tests for erjang.

@josevalim
Copy link
Member

@krestenkrab exactly!

@vanstee
Copy link
Contributor Author

vanstee commented Dec 2, 2013

Yeah, let's not make this assumption. Let's check explicitly with Keyword.has_key?/2!

Cool. Sounds good. Do we need a way for [tag: nil] to be passed in from the command line?

@josevalim
Copy link
Member

Cool. Sounds good. Do we need a way for [tag: nil] to be passed in from the command line?

Not from now. But it can always be set directly via ExUnit.configure/1.

Copy link
Member

Choose a reason for hiding this comment

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

Can we add a section to this documentation named ## Filters explaining what is the supported command line syntax and linking to ExUnit.Case docs for more information?

Copy link
Member

Choose a reason for hiding this comment

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

Similarly, we should update the tags section in the ExUnit.Case module docs to mention filters and simply say options can be passed via command line as well with mix test. :)

@vanstee
Copy link
Contributor Author

vanstee commented Dec 3, 2013

List of things to fix:

  • Remove need for filter in CLIFormatter.Config
  • Guarantee that tags and filter are never nil
  • Move parse_filters over to ExUnit and add some tests
  • No longer split for more than one :
  • Support exclusion filters
  • Handle the case where the value of a tag is nil
  • Fix print filters to know about inclusion and exclusion of each filter
  • Update and improve documentation in the mix task and ExUnit.Case

I hope I didn't muck this up too much, but I also changed how filters work slightly compared to #1898 to match how they are implemented in rspec.

Specifically this part changed slightly:

Basically, if a test has a tag :win32 and there is a filter for that particular tag and the value of the tag does not match the value of filter, the test is skipped.

Now when defining an inclusion filter (the normal version without the ~ prefix) only the tests with the exact tag and value will be run. This means tests that do not have any tags will not be run.

Let me know how you feel about the change or if a better example would make it more clear. I'd be happy to switch it back over to what was originally spec'd out. Thanks for all the feedback so far!

@ericmj
Copy link
Member

ericmj commented Dec 3, 2013

Now when defining an inclusion filter (the normal version without the ~ prefix) only the tests with the exact tag and value will be run. This means tests that do not have any tags will not be run.

We should ignore the tags that the filter does not concern, i.e. if you filter adapter:pg we should run all tests except those where tag is adapter and the tag value is not pg.

We could support your proposal through --only adapter --filter adapter:pg.

@vanstee
Copy link
Contributor Author

vanstee commented Dec 3, 2013

@ericmj Cool I'll go ahead and switch that back. When using an exclusion filter, ~adapter:pg for example, should we run all tests except those where tag is adapter and the tag value is "pg"?

@ericmj
Copy link
Member

ericmj commented Dec 3, 2013

@ericmj Cool I'll go ahead and switch that back. When using an exclusion filter, ~adapter:pg for example, should we run all tests except those where tag is adapter and the tag value is "pg"?

Yes 👍

Copy link
Member

Choose a reason for hiding this comment

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

Ok, now we are actually printing those filters as tuples. Maybe we should consider a different way to print that?

@josevalim
Copy link
Member

Sweet @vanstee!

The issue with supporting ~adapter:pg and converting them to filters is that now we need to reconsider how we are going to print this stuff, as they are now tuples internally (I have added some comments related to that). Printing the tuples themselves would be weird and not very helpful:

Using filters: [{ :os, "win32", true }]

Any suggestions? Because I don't have any. :D

@vanstee
Copy link
Contributor Author

vanstee commented Dec 7, 2013

@thomas-holmes and I were discussing how filters should work with multiple tags. Here are some examples we walked through:


mix test --filter os:unix --filter os:win32

With the current rules I would assume all tests that either don't have an :os tag or have an :os tag that equals either "unix" or "win32" will be run.


When using multiple filters with different tags, I think most people would expect these rules to be anded together. So for this test, I would expect the following results:

mix test --filter type:unit os:win32
run tags
x []
x [os: "win32"]
[os: "unix"]
x [type: "unit"]
[os: "win32", type: "integration"]
[os: "unix", type: "unit"]
x [os: "win32", type: "unit"]

Is this what you had in mind?

Also it might be nice for either the inclusion or exclusion to be "exclusive" since we really have no way of running only tests with a specific filter (skipping those without tags or with different tags).

@josevalim
Copy link
Member

That's a very good point and I agree with the semantics! The only remaining concern right now is the configuration options (i.e. how we are going to configure but not through the command line) and how to print the filters with different combinations. Here is one approach:

We can provide a reject option besides the filter one:

ExUnit.configure reject: [type: "slow"], filter: [os: "unix"]

Running tests would print:

Filtering tags: [os: "unix"]
Rejecting tags: [type: "slow"]

Then, through the command line, we can get rid of the ~ semantics in favor of explicit --filter and --reject options. If an option is given more than once, it is accumulated and has or semantics.

Another approach would be to replace the words filter and reject by including and excluding. The end result is the same, just how we are going to call them changes. How does this sound?

@vanstee
Copy link
Contributor Author

vanstee commented Dec 9, 2013

I like it. I'll throw this together and see how it looks.

@krestenkrab
Copy link
Contributor

I'd prefer using include/exclude rather than filter/reject, as the meaning is much more clear.

In particular the word "filter" could be interpreted to mean either include or exclude.

Sent from my iPhone

On 07/12/2013, at 11.03, "José Valim" <notifications@github.commailto:notifications@github.com> wrote:

That's a very good point and I agree with the semantics! The only remaining concern right now is the configuration options (i.e. how we are going to configure but not through the command line) and how to print the filters with different combinations. Here is one approach:

We can provide a reject option besides the filter one:

ExUnit.configure reject: [type: "slow"], filter: [os: "unix"]

Running tests would print:

Filtering tags: [os: "unix"]
Rejecting tags: [type: "slow"]

Then, through the command line, we can get rid of the ~ semantics in favor of explicit --filter and --reject options. If an option is given more than once, it is accumulated and has or semantics.

Another approach would be to replace the words filter and reject by including and excluding. The end result is the same, just how we are going to call them changes. How does this sound?


Reply to this email directly or view it on GitHubhttps://github.com//pull/1909#issuecomment-30051774.

@josevalim
Copy link
Member

@vanstee any news? :)

@vanstee
Copy link
Contributor Author

vanstee commented Dec 16, 2013

@josevalim Still need to finish up the documentation and message when running tests. How does this look so far?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@josevalim Any thoughts on how to improve this? The permutation part at the beginning and the reduce might be a little hard to follow.

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, the reduce seems perfectly clear to me, absolutely out of context. It’s a common pattern for dictionary iteration/building. As I understand it you’re trying to do two things in the reduce:

  • consolidate duplicate keys, favoring order of insertion but preferring truthy values
  • convert a ListDict to a HashDict

HashDict.new accepts ListDicts and a transformation function and the Keyword module has utilities for handling ListDicts with duplicate keys, but scanning through their docs I don’t think there’s anyway you could use them to get the same behaviour while only iterating over the collection once.

As for the permutation stuff, I’d use list comprehensions:

results = lc filter inlist Dict.keys(filters), tag inlist Dict.keys(tags), do: evaluate_filter(filter, tag)

Christopher Keele
Sent with Sparrow (http://www.sparrowmailapp.com/?sig)

On Monday, December 16, 2013 at 1:54 PM, Patrick Van Stee wrote:

In lib/ex_unit/lib/ex_unit/runner.ex:

  • Enum.map filters, fn filter -> > + { { elem(filter, 0), elem(tag, 0) }, evaluate_filter(filter, tag) } > + end > + end > + > + results = Enum.reduce results, HashDict.new, fn { key, evaluation }, dict -> > + Dict.update dict, key, evaluation, &(evaluation || &1) > + end > + > + mismatch = Enum.find Dict.to_list(results), &match?({ _, false }, &1) > + > + case mismatch do > + { { _, tag }, _ } -> { :error, tag } > + _ -> :ok > + end > + end
    Any thoughts on how to improve this? The permutation part at the beginning and the reduce might be a little hard to follow.


Reply to this email directly or view it on GitHub (https://github.com/elixir-lang/elixir/pull/1909/files#r8379268).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

FWIW, the reduce seems perfectly clear to me

Sweet!

...but scanning through their docs I don’t think there’s anyway you could use them to get the same behaviour while only iterating over the collection once.

Yeah I was looking for some kind of merge function to use as well but this seemed like a decent alternative.

As for the permutation stuff, I’d use list comprehensions:

Good call! Thanks.

@vanstee
Copy link
Contributor Author

vanstee commented Dec 17, 2013

Almost done. Just need to improve the docs a little more.

Let me know if you have suggestions to improve anything implementation related.

@josevalim
Copy link
Member

@vanstee this looks awesome! Let us know when it is ready and so we can merge it!

@vanstee
Copy link
Contributor Author

vanstee commented Dec 18, 2013

@josevalim I think this is finally done! Feel free to make any changes. Hope the docs aren't too verbose. 💚

@josevalim
Copy link
Member

Thank you! I will merge it soon and it will be in the next release! :)

josevalim pushed a commit that referenced this pull request Dec 31, 2013
@josevalim josevalim merged commit 1622eb6 into elixir-lang:master Dec 31, 2013
@josevalim
Copy link
Member

Merged, thank you! ❤️

@vanstee vanstee deleted the exunit-support-filters branch December 31, 2013 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Support ExUnit filters

5 participants