-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Report coverage for Unit-returning suspend funs in Kotlin 1.3.60 correctly #1019
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
base: master
Are you sure you want to change the base?
Conversation
b08f3d5 to
1a33912
Compare
|
I updated the PR from master and reworked the fix based on Evgeny Mandrikov's fix for the same problem - the only thing I found missing is that the |
It corresponds to non-suspended exit from a function, so either will be executed or function infinitely suspends. In both cases coverage is consistent with non-suspending functions, while won't after your change: |
|
@Godin You're right about indefinitely suspending functions, but there is one case you've missed: The private suspend fun b2() {
yield()
}then the return of In some instances it's possible to write tests that trigger both paths, but if there's no control over the I'm not sure how to filter this case while maintaining consistent behaviour with non-suspending functions, filtering the return altogether is the only thing I could come up with... Do you have a better idea? |
1a33912 to
36caf7b
Compare
Release 0.8.7
When the Kotlin 1.6.30 compiler encounters a
Unit- returningsuspend funthat forwards to calling anotherUnit- returning suspend fun as its last statement, and doesn't have other calls tosuspend funs, then it generates a ternary operator that can often not be covered in testing:The Bytecode generated for
b()is:which decompiles to Java as follows
The ternary operator that can be seen in the decompiled Java code can often not be covered; so the whole ternary operator should be excluded from coverage.
This PR addresses this issue by searching for calls to
IntrinsicsKt.getCOROUTINE_SUSPENDED(), followed by the instructionsIF_ACMPNE L1,ARETURN,L1,POPwithL1being the Label theIF_ACMPNEinstructions jumps to. It then ignores all four instructions (IF_ACMPNEtoPOP, inclusively).It furthermore ignores the
return Unit.INSTANCEpart, being theGETSTATICand the followingARETURNinstruction, because returningUnitcan not be asserted in Kotlin anyway.Note: the
return Unit.INSTANCEpart may or may not follow directly after thePOPlike in the given example; there may be aGOTOinstruction to jump to it, as can be seen in the tests.