-
-
Notifications
You must be signed in to change notification settings - Fork 282
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
RFC on error assertions for functions with multi-return values and trailing error value #392
Comments
Hey @thediveo sorry for the delay. I like pulling out Here's a first sketch of what this might look like. We keep the default behavior but extend
I think that could be pulled off in a largely backward compatible way. Thoughts? |
Looks good to me! Errxpect (sorry for the name) was kind of a proof of concept on my side trying to mangle things into Gomega without me having any clue, and before starting to ask questions here. |
......any interest in pulling together a PR? 😉 😬 |
hehe, I can try, but right now I'm lost as to how the |
I'm imagining it looks like overhauling the implementation over at https://github.com/onsi/gomega/blob/master/internal/assertion/assertion.go to enable the chaining I outlined above. I can get to this eventually, so no worries - though i'm trying to focus my free coding time (which there isn't too much of due to covid and in-person schooling being closed!) on Ginkgo 2.0 right now... but if you have time to give it a shot, I'd start there. |
After finally getting more into the details I recon that today However, if we can live with "only" a single pick per Aside from these questions: for chaining, would it be okay to introduce to assertions an "original-derived" relationship? So that |
hey @thediveo thanks for bumping this. I've learned a lot working on Ginkgo 2.0 since my original comment - a pattern/approach that I've found to be flexible and powerful is to use Typed Parameters to extend the DSL. It's how the new Ginkgo 2.0 decorators are implemented. I think it would apply nicely here. The basic idea would be to extend Expect(foo(42)).To(Equal(41), HaveNthValue(1, Equal("42")), HaveLastValue(MatchError("DOH!")) Under the hood I imagine a new type: type GomegaIndexer struct {
IndexRange [2]int
Matcher GomegaMatcher
} And DSL functions like This would have some additional benefits. You could finally do stuff like: Expect(42).To(BeNumerically(">", 40), BeNumerically("<", 42)) without having to use the All this allows us to maintain the current behavior, including the (somewhat gnarly) On the Expect(multiReturnFunction(), WithOffset(2), WithTimeout(time.Minute)).To(...)) This will return a compilation error. So the approach taken so far to extend the return value of Thoughts? |
I've read more into your use of decorators (functions) for Ginkgo in order to get a feeling how you are intending to apply them to Gomega's realm. While I definitely see the benefit for Ginkgo (while still prefering a quickly done "FIt" over "It(..., Focus)") I'm not yet sure that applying them to Expect()ations looks as straightforward as in case of Ginkgo. Maybe, because the already existing matcher infrastructure looks like decorators to some degree. We basically have two separate usages of
In your |
Just the usual after-thought about multiple return values versus named structure fields. What about something slightly crazy, such as, now also auto-checking for the usual error idiom in the sense of all values can be non-zero, but not the final one: Expect(foo()).As("bar", "baz", "err").To(HaveValue("bar", Equal(42)), HaveValue("baz", Equal(666)))
|
hey - I just went back and reread the original issue up top and am realizing that I've misunderstood what you were proposing all along! I must have been reading it quickly or jumped through a bunch of unspoken assumptions on my part, but I ended up thinking the use case is "making arbitrary assertions against multiple return values within a single But now I see that the use case is "there are times when I want to assert that an error has occurred (or matches a specific error) and that all the other return values are nil/zero-valued" - which.... makes more sense. Sorry for the confusion! I generally agree that Now that we're on the same page (my bad!) I can see adding Sorry again for misreading your original issue. It's been quite the journey to get here but I think we're on the same page now! |
No need for sorry, as you helped me with your reasoning from a different perspective to clarify my own thinking. I cannot tell how often as a system architect I need to kick myself about unspoken and seemingly obvious assumptions... |
lol so true. thanks! if you're still up for working on a PR that would be great. I literally just wrote some code where I thought "hey that .Error() thing would be useful here" |
will gladly do, especially we now have a clear view on it. If only most parts of our projects could be like this... 😆 |
@onsi would you mind me slightly refactoring type Assertion struct {
actuals []interface{}
actualIndex int
offset int
g *Gomega
} and then adding a Would this be fine to you? Any suggestions? |
yes this makes sense to me and is probably how I'd approach it. thanks for checking! Doing this for |
I pondered about |
I think I buy that. It's rare that I need to assert that "eventually an error starts occurring". |
We can provide |
thanks for the PRs @thediveo - these are great additions to Gomega! I'll cut a new minor release soon/next week. I'm working on a new matcher that i'd like to include in the next release alongside these changes. |
I've noticed that I forgot to make a PR for the |
Gomega actually was my life-saver when starting with Golang, after having had a pleasant experience with Lua busted and its DSL. As I was looking around how big Go projects do it, I was steered towards Gomega and felt right at home. So thank you very much for Gomega in the first place! |
❤️ thanks for the kind shout out! Once you get the Unrelated BTW I just pushed a new |
I could actually see use for the opposite: What a good feeling to close an issue as resolved 😁 🎉 . |
This is a request for comment on extending Gomega to more smoothly handle (phrase) error assertions for functions which return multiple values, including a trailing error. While working on my Gomega 3rd party extension "errxpect" (https://github.com/TheDiveO/errxpect) I noticed some things and I would like to get feedback on ways to do it better or if gomega could be opened to 3rd party implementors of
gomega.Assertion
.So, instead of:
simply spell it out as:
Things I noticed and had to work around:
Gomega's internal implementation of
gomega.Assertion
basically does two separate things of relevance to our discussion here:gomega.Assertion
probably would like to tap into ("inherit").Gomega's
ExpectWithOffset
pattern cannot be applied to multi-return value functions. This actually can be easily remedied with a genericWithOffset(o int)
function added to thegomega.Assertion
interface. In my errexpect module I return a more specially typed assertion object, which then offersWithOffset(...)
, so I don't need to touch Gomega'sAssertion
interface.My questions for feedback:
At the moment I have to get Gomega's assertion functionality for triggering fail handlers and producing stack context information by running a transient, separate assertion when checking the multiple return values for calling the user's matcher(s). Could you imagine opening up the functionality for triggering fail handlers and stack context traces to 3rd party implementers of
Assertion
?With me coming up with
Errxpect
I'm throwing stones in my glasshouse ... but sinceExpectWithOffset(...)
slightly stutters and with Option receivers being all the rage, could you imagine a genericAssertion.WithOffset(o)
, so Gomega's assertions/expectations can also be spelled out asExpect(...).WithOffset(1).To(...)
?The text was updated successfully, but these errors were encountered: