Conversation
Eventually, Never and EventuallyWithT dereference `condition` on a goroutine they spawn, so a nil condition panics somewhere the caller's recover cannot reach, and the whole test binary goes down. All three also hand `tick` straight to time.NewTicker, which panics on a non-positive interval, even though the ticker is only ever read after the first result. matchRegexp type-asserts before dereferencing, so a typed nil *regexp.Regexp passes the assertion and then crashes. Guard all three and report a failure with a message, which is what the rest of this package already does: isFunction, a few lines above matchRegexp, returns false for a nil argument rather than dereferencing it. A nil regexp has no pattern, so nothing can match and it is reported as no match, leaving Regexp to fail and NotRegexp to pass. Signed-off-by: feiiiiii5 <feiiiiii5@users.noreply.github.com>
No behaviour change: stripping comments and blank lines from both revisions leaves them byte for byte identical, and the package's tests still pass. The tick comment said the ticker "is only ever read after the first result", which is true of the tickC channel but reads as though a bad interval would therefore be harmless until the first result. It is not: time.NewTicker is called before the condition has run at all and panics on a non-positive interval, in the caller's goroutine, which aborts the run rather than failing one assertion. The nil-condition comment explained the crash but not the choice. Never could plausibly be read as vacuously satisfied by a nil condition, returning true. It deliberately fails like Eventually does, so that one malformed argument behaves the same way in all three entry points; that is worth saying where the check is.
dolmen
left a comment
There was a problem hiding this comment.
The nil Regexp case must be handled in a separate PR.
The two causes are unrelated: one is a nil condition reaching a goroutine this package spawns, the other a typed nil arriving at a type assertion in matchRegexp. Splitting them so each can be reviewed on its own; the Regexp case moves to its own pull request.
|
Split, as asked: #1971 is left with only the nil #1972 carries just I put the two in separate commits rather than rewriting the branch, so the split is visible in the history. For the second one, the regression on
If the split is not what you had in mind — or if the second one is better as a third change on top of #1971 than as its own pull request — say so and I will rearrange it. |
Summary
Eventually,NeverandEventuallyWithTpanic instead of reporting a failure whenconditionis nil ortickis not positive, andRegexp/NotRegexppanic on a typed nil*regexp.Regexp; this guards all three.Changes
Eventually,Never,EventuallyWithT:Failwith a message whencondition == nilortick <= 0, before the ticker is built and before the goroutine is spawned.matchRegexp(used byRegexpandNotRegexp): a typed nil*regexp.Regexpis reported as no match instead of being dereferenced.Motivation
A nil condition panics on a goroutine these functions spawn, so it is not something the caller can
recover():One nil that reaches a helper takes the whole test binary down, with the stack trace pointing into testify rather than at the offending call.
tick <= 0reachestime.NewTickerand panics withnon-positive interval for NewTicker. The ticker is only ever read after the first result (tickCstarts nil, and is only assigned in thecase v := <-chbranch), so a non-positive interval can never be useful — it is created unconditionally, before it can be known to be needed.The nil-guard pattern is already in this file:
isFunction, a few lines abovematchRegexp, returnsfalsefor a nil argument instead of dereferencing it, which is whyassert.Equal(t, nil, someFunc)reports a failure rather than crashing.I went with a failure report rather than a panic with a better message, because that is what every other assertion in this package does. If you would rather
tick <= 0mean "check once, then wait for the timer" — which the existingtickC = nilmechanism could express without a ticker at all — that is a small change on top and I am happy to switch to it.For the typed nil regexp I only added the crash guard, which means
Regexp(t, (*regexp.Regexp)(nil), s)fails with a message that renders the nil pointer rather than saying "nil regexp". An explicit guard in the two public functions would read better; I left that out to keep the diff to the crash.Tests fail on
87a7b9dby aborting the binary with exactly the trace above, and pass with the fix:Full suite green on both this branch and
87a7b9d(8 packages), and green here under-race.gofmt -l .andgo vet ./...are clean.Related issues
Refs #1970
I did not use
Closeson purpose: that issue also asks whether nil guards are wanted for a separate family (Subset,ElementsMatch,IsIncreasingand friends, whereSubset/NotSubsetwere reported in #1918 and closed without a comment). That question is still open and this PR should not close it.