New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Be date spec comparator #226
Conversation
Hi, @treble37 ! |
Hi @antonmi, just a few things...
|
Oh, sorry! |
Hi, @treble37 !
Also, could we think about improvements of be(:>, ...) and be(:<, ...) mathers? So they use the same comparison logic. Thank you! |
@zeeker you are very welcome! |
Hi @zeeker - your input would be welcome, I have a feeling there are things that can be improved, so please review away and don't be shy! |
I will, lot's of meetings today! |
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'm asking myself if there is no native way of doing this. DateTime.diff/3
only works for seconds and below but isn't there something else?
Most of the stuff is of cosmetic nature, feel free to dismiss those.
lib/espec/comparator/diff.ex
Outdated
end | ||
end | ||
|
||
defp do_diff(a, a, type), do: zero(type) |
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.
The alignment of the do:
seems to be off here.
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.
Adjusted in accordance with #226 (comment) (If you use the do: syntax with functions and the line that makes up the function body is long, put the do: on a new line indented one level more than the previous line.
)
lib/espec/assertions/be_close_to.ex
Outdated
@@ -5,6 +5,12 @@ defmodule ESpec.Assertions.BeCloseTo do | |||
it do: expect(2).to be_close_to(1, 3) | |||
""" | |||
use ESpec.Assertions.Interface | |||
alias ESpec.Comparator.Diff |
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.
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.
Space added between use and alias
lib/espec/assertions/be_close_to.ex
Outdated
alias ESpec.Comparator.Diff | ||
|
||
defp match(subject, [value, {granularity, delta}] = data) do | ||
result = abs(Diff.diff(subject, value, granularity)) <= delta |
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.
One could write that as follows but I'm not sure if that's a clearer approach; I'll mention it for completeness sake.
result =
subject
|> Diff.diff(value, granularity)
|> abs()
|> Kernel.<=(delta)
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.
thanks, I like this and will use it.
lib/espec/assertions/be_close_to.ex
Outdated
|
||
defp match(subject, [value, {granularity, delta}] = data) do | ||
result = abs(Diff.diff(subject, value, granularity)) <= delta | ||
{result, result} |
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 return the result
boolean twice you could return the result
and the real delta. I'm aware that the original implementation didn't do that but I think it would be a great improvement!
Then you could use this in the success_message
and/or error_message
to inform the user about the real delta which might help in finding the issue.
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.
Preliminary interface for providing a real computed delta with an error message added...
lib/espec/comparator/diff.ex
Outdated
end | ||
defp do_diff(a, b, :years) do | ||
diff_years(a, b) | ||
end |
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.
The community style guide suggests to only use single line do
s if you have at maximum one multi line do
. I would suggest changing this two to single line do
s.
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.
Adjusted in accordance with #226 (comment) (If you use the do: syntax with functions and the line that makes up the function body is long, put the do: on a new line indented one level more than the previous line.
)
lib/espec/comparator/diff.ex
Outdated
if a > b do | ||
diff_years(end_date, start_date, 0) | ||
else | ||
diff_years(start_date, end_date, 0) * -1 |
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.
Maybe also call this do_diff_years
to match the approach of the diff_months
implementation?
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.
Will change, thanks!
lib/espec/comparator/diff.ex
Outdated
diff_years(a, b) | ||
end | ||
defp do_diff(_, _, granularity) when not granularity in @units, | ||
do: {:error, {:invalid_granularity, granularity}} |
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.
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.
Adjusted in accordance with #226 (comment) (If you use the do: syntax with functions and the line that makes up the function body is long, put the do: on a new line indented one level more than the previous line.
)
lib/espec/comparator/diff.ex
Outdated
defp do_diff(_, _, granularity) when not granularity in @units, | ||
do: {:error, {:invalid_granularity, granularity}} | ||
|
||
defp diff_years(a, a), do: 0 |
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.
Is there actually a case where this will happen? Wouldn't this have been caught on line 23? Same for diff_months
.
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.
great catch Zeeker, will change
lib/espec/comparator/diff.ex
Outdated
12 | ||
end | ||
(year_diff*12)+month_diff | ||
end |
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'm not sure, but wouldn't it be possible to reuse the diff_years
function to reduce complexity in do_diff_months
?
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.
@zeeker - If I'm understanding you correctly, the current implementation of diff_years that I think you're talking about (listed below) assumes a and b are date(times) converted to gregorian microseconds rather than integer years.....
defp diff_years(a, b) do
{start_date, _} = :calendar.gregorian_seconds_to_datetime(div(a, 1_000*1_000))
{end_date, _} = :calendar.gregorian_seconds_to_datetime(div(b, 1_000*1_000))
if a > b do
do_diff_years(end_date, start_date, 0)
else
do_diff_years(start_date, end_date, 0) * -1
end
end
@zeeker , thank you very much for detailed comments! |
f0196d5
to
04c7ef7
Compare
9b2bbed
to
5e4791b
Compare
Ok @antonmi (and @zeeker), this PR is getting close to done (other than some minor documentation cleanup), but I would like some feedback regarding your comment:
Commit 9b5d91d is my attempt to do this. What do you think of this API? If you're fine with it, then I will add the necessary tests to implement. |
Hi, @treble37 ! Thanks for your awesome work! What I meant was use the Comparator.diff when dates are passed to the Like this: defp match(%Date{} = subject, [op, %Date{} = val]), do: match_date_times(subject, [op, val])
defp match(%Time{} = subject, [op, %Time{} = val]), do: match_date_times(subject, [op, val])
defp match(%DateTime{} = subject, [op, %DateTime{} = val]), do: match_date_times(subject, [op, val])
defp match(%NaiveDateTime{} = subject, [op, %NaiveDateTime{} = val]), do: match_date_times(subject, [op, val])
defp match_date_times(subject, [op, val]) do
delta = subject |> Comparator.diff(val, :seconds)
result = apply(Kernel, op, [delta, 0])
{result, result}
end But your API implementation is also very cool! |
9b5d91d
to
44e885e
Compare
Hey @treble37, I can only join antomni in saying thank you for your work and patience, and I'm glad I could be of some help. I just have one final suggestion. In addition to the current This would allow for the following syntax: expect date |> to(be :>, other_date, years: 1) I'll link in a second, I'm on mobile right now. |
See commit ae7a4ca for details of what I mean. |
ok @zeeker, thank you for your review and suggestion(s) as always; regarding I will work on adding the equivalent ExUnit tests and doing a final cleanup in the next 2 weeks or so then... |
For issue antonmi#111 "Add Calendar expectation"
This reverts commit e694572. Import Timex logic to compare Date types and use a different API for Date type comparison
Change ESpec.Protocol to ESpec.DateTimeProtocol
Using the to_gregorian_microseconds interface - This is a bit misleading since we're really just converting the time to microseconds, it has nothing to do with gregorian
Add tests to be able to compare microsecond granularity for DateTime and NaiveDateTime
Avoid warnings such as: "undefined protocol function to_gregorian_seconds/1 (for protocol ESpec.DateTimeProtocol) lib/espec/datetime/datetime.ex:1"
Tests passing with Elixir 1.5.1 only
Tests passing for Elixir 1.4.5 (and 1.5.1) This commit is to backport Elixir 1.5.1 functionality via the Calendar.ISO.Extension module
This commit is to backport Elixir 1.5.1 functionality via the DateTime.Extension and Integer.Extension modules
Let's not rely on the version of Elixir to decide what method to call. Instead, we'll use one common method for all. Once ESpec migrates to supporting >= Elixir 1.5.x, then we can probably remove some of this supporting code.
Move this functionality into its own module, Espec.DatesTimesComparator
Help the user hunt down errors by providing the actual computed delta
Move file into dates_times folder for organizational clarity
Use the Comparator.diff when dates are passed to the be assertion. This lets us have the same comparison logic as the be_close_to assertion(s).
Enable testing syntax such as `expect date |> to(be :>, other_date, years: 1)`. Also, update tests to accomodate this new syntax.
Move one of the context descriptions in the describe text to avoid unneccessary block nesting
The dates_times files deal with assertions for Elixir's Date/DateTime/NaiveDateTime/Time types, so move it here.
Remove redundant variables
Also, fix typo in error message
Since we ported over Types from the Timex hex package, let's remove the unused types
9d14fca
to
a99a448
Compare
ok @antonmi and @zeeker, this PR is now updated with the functionality and I addressed yours and Zeeker's comments (which I put in the checklist up top #226 (comment)), so I guess it's ready to merge unless you have any other comments? I can bump the version to |
Awesome work @treble37! Semantic versioning would suggest to bump the version to 1.5.0 since you introduce a backwards compatible feature. Those are just my two cents though. |
Update changelong in README Remove some minor warning messages as tests are run
Of course you are right @zeeker - version bumped to 1.5.0 (maybe I shouldn't have had that last |
ESpec 1.5.0 is live! |
For #111
Let's say ESpec.DatesTimes. And place the code into dates_times directory.
(Be date spec comparator #226 (comment))