-
-
Notifications
You must be signed in to change notification settings - Fork 287
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
gstruct should allow for default matching mixed with customized matching. #197
Comments
@timstclair wdyt? |
I agree this would be useful, but have an alternative proposal: wildcard field names. The simplest would be to just treat I don't like option 4, since for my usecase I actually do want it to be an error if matchers weren't provided for all fields. The reason is I want to make sure all fields in a struct have a test, and if another developer adds a new field to the struct, I want to require them to update the test. |
Better ProposalNow that I think about it some more, I'm not sure my understanding of gstruct was entirely correct, and I'm not sure how useful wildcard matchers would be, given your declarative model. I agree they might find some use, but I can't see it being terribly common, and it's orthogonal to what I actually wanted (sorry about that!). So, with that in mind, here is a more clear proposal: As it stands, Expect(actual).To(MatchAgainst(expected, Fields{
"Foo": Ignore(),
"TimeField": Custom(timeEquals),
"SomeNumberField": BeNumerically(">", 1), //they don't have to match, this just has to be higher than some value
"SomeNestedStruct": MatchAgainst(expected.SomeNestedStruct, Fields{
"Bar": Ignore(),
//everything else for actual.SomeNestedStruct <-> expected.SomeNestedStruct uses reflect.DeepEqual
},
//everything else for actual <-> expected uses reflect.DeepEqual
})
timeEquals := func(actual interface{}, expected interface{}) (bool, error){
timeActual, ok := actual.(time.Time)
if !ok { /* ... */ }
timeExpected, ok := expected.(time.Time)
if !ok { /* ... */ )
return timeActual.Equal(timeExpected), nil
} |
Yes, I think you're right about the issue with the wildcard matchers. IIUC, you're looking for something like "deep equal with override". I can see the use of that, your proposal makes sense. Would this only be for struct (fields) matchers? It's a little harder to envision how it would work with a slice (elements) matcher. |
I'm not sure, I'd have to dig into it a bit. Conceivably you could have another method that simply doesn't take an expected and returns a closure that you pass the slice element to, but that wouldn't work beyond the first level, really. I feel comfortable saying that, if someone wants to apply |
Any thoughts on this one y'all? Anyone up for a PR? |
I've been meaning to take a crack at it, but I haven't had time. Should have some free time next week to dig in. |
@flowchartsman Seems like you never got around to this, do you still use gomega? Is this still something that would be valuable to you? |
I do, but in a much more limited capacity. I think it would be exceptionally useful, but I'm exceptionally busy and would need to reacquaint myself with the code. If anyone is willing to pair up and hack on it some weekend, I'm game. |
Currently gstruct allows you to do one of the following
It would be even more useful if there was an additional option to provide custom matchers for certain fields and fall back to
reflect.DeepEqual
if a matcher isn't specified. This would allow for elegant handling of certain edge-case fiddliness like you sometimes see withtime.Time
There are four ways I can see this being handled
MatchAllFieldsWithDefault
MatchFields
,AllowDefault
MatchAllFields
,Fallback
orUseDefault
MatchAllFields
to usereflect.DeepEqual
if a matcher is not providedPersonally, I feel like 4 is the right choice because it seems unnecessary to have an additional error condition for "hey, you didn't provide matchers for everything" when the docs already specify that it requires all fields be matched. It seems like it would be in keeping with the spirit of the library if
MatchAllFields
matched everything, whether you remembered to set a matcher or not. Following that, 1 is probably the next best choice, as it changes no behavior.The text was updated successfully, but these errors were encountered: