Consider the following minimal Kotlin example:
fun <U> someWrapper(supplier: () -> U): () -> (U) {
return { supplier() }
}
fun foo(taskExecutor: TaskExecutor): Int {
val future = CompletableFuture.supplyAsync(someWrapper {
42
}, taskExecutor::execute)
return future.join()
}
@Test
public void shouldFoo() {
assertThat(foo(), is(42));
}
I have branch coverage rules in Jacoco, which fail for the code above, saying 1 of 2 branches is not covered on the line of the someWrapper
call. Unfortunately, it is not an option for me to exclude all classes from which someWrapper
is called.
Looking at the decompiled Java code:
public final int foo(TaskExecutor taskExecutor) {
Object var10000 = WrappersKt.someWrapper((Function0)null.INSTANCE);
if (var10000 != null) {
Object var2 = var10000;
var10000 = new Foo$sam$java_util_function_Supplier$0((Function0)var2);
}
Supplier var3 = (Supplier)var10000;
Function1 var4 = (Function1)(new Function1(this.taskExecutor) {
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1) {
this.invoke((Runnable)var1);
return Unit.INSTANCE;
}
public final void invoke(Runnable p1) {
((TaskExecutor)this.receiver).execute(p1);
}
public final KDeclarationContainer getOwner() {
return Reflection.getOrCreateKotlinClass(TaskExecutor.class);
}
public final String getName() {
return "execute";
}
public final String getSignature() {
return "execute(Ljava/lang/Runnable;)V";
}
});
CompletableFuture future = CompletableFuture.supplyAsync(var3, (Executor)(new Foo$sam$java_util_concurrent_Executor$0(var4)));
var10000 = future.join();
Intrinsics.checkExpressionValueIsNotNull(var10000, "future.join()");
return ((Number)var10000).intValue();
}
I think, the problem is the if (var10000 != null)
branch, which is even marked by the IDE to be unnecessary (always true).
Is it somehow possible to adjust the code such that it is possible to cover all branches, eg. by making sure the compiler does not generate that extra null check? I can change the code of both foo(..)
and someWrapper(..)
as long as I am able to supply a decorated lambda.
I use Kotlin 1.3.50 and Jacoco 0.8.4.
EDIT.
One obvious workaround is to extract supplyAsync(someWrapper { ... })
to some utils class and exclude that class only, ie.:
fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}
This would be good enough for me, though I am still curious why the branch is added by Kotlin, where no branch need to be.