JaCoCo has long-standing issues with covering calls of methods that throw 
exceptions.
When such methods are called inside of, if/else branches for example, the 
result is
partial coverage reported for those branches.

However, there is a JaCoCo idiom 
(https://github.com/jacoco/jacoco/issues/370#issuecomment-267854179)
that we can use to avoid uncovered code in those cases. The basic idea is to 
create
and return an exception from a called method and throw that exception from a 
caller,
like in:

    void fail() {
      throw create();
    }

    RuntimeException create() {
      return new RuntimeException();
    }


How this relates to the Groovy assert statement? For example, for a simple 
assert
statement like

    assert firstName != null

Groovy generates something like

    ValueRecorder var1 = new ValueRecorder();

    try {
      String var10000 = this.firstName;
      var1.record(var10000, 8);
      var1.record(var10000, 8);
      if (var10000 != null) {
        var1.clear();
      } else {
        ScriptBytecodeAdapter.assertFailed(AssertionRenderer.render("assert 
firstName != null", var1), (Object)null);
      }

    } catch (Throwable var3) {
      var1.clear();
      throw var3;
    }

The problem with generated code is a

    ScriptBytecodeAdapter.assertFailed(AssertionRenderer.render("assert 
firstName != null", var1), (Object)null);

method call. Inside that method, an exception is created and thrown. Since 
JaCoCo cannot
cover that line completely, the branch

    if (var10000 != null)

will be reported as partially covered.

To avoid those issues, ScriptBytecodeAdapter.assertFailed() can be adapted (or 
a new
method can be introduced) to return the exception instead of throwing it. And 
then,
the calling generated code can throw that returned exception.

I have a small project demonstrating the issue and a possible solution here:
https://github.com/dmurat/groovy-assert-jacoco-coverage-problem

What do you think?

Tnx

Reply via email to