-
-
Notifications
You must be signed in to change notification settings - Fork 58
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
Revisiting is.Equal
and the role of reflect.DeepEqual
#53
Comments
#49 is somewhat related to this issue. |
Ah, yes, good ol' monotonic time. One of my least favorite stdlib hacks. As you've probably already discovered from your research, time equality is potentially tricker than it might at first appear, and other testing libraries have struggled with this and potential fixes and their implications. Taking a look at the options:
Easy enough at the value level, but would break again when comparing structs that contain a
This seems like a good compromise approach until you consider that it would essentially involve recreating Personally, I'd lean towards a version bump even for this, as I am very averse to breaking even the smallest number of tests in the field, so at that point you might as well swing for the fences and consider:
This is probably the most robust, future-proof approach, since it leverages the work on a. ignore them outright, or Of these two, Which forces us to consider how to handle I don't have the perms for this, but I'll ping @matryer, and we can talk about getting that ball rolling. To provide @willbicks with a bit of direction in the meantime, Footnotes
|
Of course, if there's another short-term approach I've overlooked, feel free to chime in with suggestions, but we probably still want a V2 discussion started. |
is.Equal
and the role of reflect.DeepEqual
Maybe the implementation for the equality check could be made configurable. This equality check function would then be called instead of I guess, the signature would be the one of equal := func(x, y any) bool {
return cmp.Equal(x, y)
} since the signatures are not the same. In regards to #49, I am more than happy to follow the |
This is a very interesting thread, so firstly, thanks for that :) A very simple solution might just be to format the time and compare the strings. Then you (the engineer) can be explicit about what's being compared. is.Equal(t1.Format(time.RFC3999), t2.Format(time.RFC3999)) How do you feel about that? |
This could potentially run afoul of timezone issues, but aside from that I think it's conceptually the same as the "just use |
This is one of those cases where API simplicity comes at the cost of hidden complexity. Saying The package documentation doesn't make any guarantees about deep equality, nor do the tests exercise it on structs, so it's not exactly like the package fails a design goal, but it also doesn't mention any potential issues, either, which makes struct equality undefined behavior. So, it's either a documentation issue solved by saying "you can do this, but sometimes it will break in thus-and-such case" (which is certainly valid, but feels unsatisfying), or it's a more invasive change. One alternative to bumping the version and going all-in on |
To me, this sounds like a rabbit hole To me, this issue as well as #49 (and with a different flavor #52) indicate, that there is a need for some better control of equality. So far, we have seen the following options to address this:
In regards to the V2 / version bump discussion, I just would like to raise the question, what would happen to the V1 in this case. Would these two version co-exist for a longer (possibly infinite) time or would V1 be declared deprecated? |
@flowchartsman how are you feeling about this one now? |
I have thoughts, but no firm conclusions yet:
I guess I'd argue we're kind of in the rabbit hole already, if you're using "simple" and This is to say that "simple" and "ergonomic" often come with a tradeoff in hidden complexity. In the case of this library, we obscure the complexity of our own reflective code behind the idiom of What this really comes down to is how we address deep equality, and what this library wants to be. To me, at least, the appeal has always been right there in bullet point number 2
To me, at least "beautifully simple" means that
This wouldn't solve the issue at hand, since
Is either a big type switch on the part of the user or it might as well be option 4.
My gut feeling on this one is that it is not beautifully simple, and that additional functional options only clutter the API surface. If we want to use go-cmp, maybe we just use it as a fallback by default. Option: Use go-cmp as a fallback to
|
I started switching from
google/go-cmp
tois
in pursuit of the latter's more pleasant and succinct syntax, but unfortunately have run into issues with how times are compared byis
.In the code being tested, a time is created using
time.Now()
, stored to a database, and then later retrieved. When comparing the two times (or the structs containing time values),is.Equal
reports that the times are different because one has a monotonic counter and the other does not. This differs from how the standard librarytime.Equal()
functions, which is recommend by the Go team instead of directly comparing time values.For example, consider the following excerpt where
time1
has a monotonic counter, andtime2
is the same time without a monotonic counter:which results in the following:
Is there a better way to handle these comparisons in
is
? Some options I can imagine include:time.Equal()
if the values being compared are times.google/go-cmp
where all "Types that have an Equal method may use that method to determine equality".google/go-cmp
library itself to perform underlying equality comparisons.The text was updated successfully, but these errors were encountered: