Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-73175

Error parsing Cobertura file for C++ project with multiple lambdas in same scope

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Minor Minor
    • coverage-plugin
    • None
    • Jenkins: 2.440.3
      Coverage-Plugin: 1.14.0
      Squish Coco: 4.3.1

      I want to use the Coverage plug-in for Jenkins for a C++ project. In said project I use Squish Coco to generate a code coverage report in Cobertura format which is then fed to the recordCoverage step of the Coverage plugin.

      In the project, there are several functions each containing several lambdas with the same signature (which is pretty common in C++, I suppose). Since those lambdas are also instrumented, they land up in the Cobertura file which, when being passed to the recordCoverage step in a Jenkins pipeline, causes an error of type:
      java.lang.IllegalArgumentException: There is already a child [METHOD] calculate::[lambda][](int) <0> with the name calculate::[lambda][](int) in [CLASS] calculate <1, LINE: 100.00% (1/1)>
      This already happens for example for the following function:

      int calculate(int value) {
          auto plusTwo = [](int x) { return x + 2; };
          auto timesTwo = [](int x){ return x * 2; };
          return timesTwo(plusTwo(value));
      }
      

       

      When instrumented, tested, and converted to a Cobertura file, this creates the following snippet inside the latter:

       

      <class name="calculate" filename="Calculate.cpp" lineRate="1.0" branch-rate="1.000000" complexity="">
        <methods>
          <method name="calculate::[lambda]" signature="[](int)" line-rate="1.0" branch-rate="1.000000">
            <lines>
              <line number="53" hits="3" branch="false"/>
            </lines>
          </method>
          <method>
            <method name="calculate::[lambda]" signature="[](int)" line-rate="1.0" branch-rate="1.000000">
            <lines>
              <line number="54" hits="3" branch="false"/>
            </lines>
          </method>
        </methods>
      </class&gt;

      One should note that the only difference in the Cobertura file between both lambdas is their line number. This snippet supposedly causes the parser error which, in turn, causes the whole pipeline step to fail. This parsing error is quite unfortunate since such code with several lambdas in the same scope is by no means exotic or rare.

      One can make the parser ignore this error by using the ignoreParsingErrors option of the recordCoverage step but this still causes two kinds of problems:

      1. The skipped parser errors are still written to the output which makes them hard to differentiate from actual hard errors.
      2. The generated Coverage report is still faulty since every lambda skipped by such a parsing error counts as "not covered" even if the Cobertura file says otherwise.

      It would therefore be desirable to either have the parser fixed to not count this scenario as error or at least have an option (or adjust the existing one?) to work around this issue by at least still providing the correct metrics in the end.

          [JENKINS-73175] Error parsing Cobertura file for C++ project with multiple lambdas in same scope

          dani added a comment - - edited

          We run into the same problem with Ruby and JavaScript code coverage. This used to work in the past but started failing when we upgraded the coverage plugin (1.6.0 -> 1.13.0) and deactivated the deprecated code coverage plugin (4.7.0).

          Ruby

          We are using the simplecov-cobertura formatter and the coverage report contains two classes with the same name:

          grep consultants_controller tmp/ci_reports/coverage/coverage.xml
                  <class name="consultants_controller" filename="app/controllers/admin/consultants_controller.rb" line-rate="0.67" complexity="0">
                  <class name="consultants_controller" filename="app/controllers/consultants_controller.rb" line-rate="1.0" complexity="0"> 

          Which causes the following error on Jenkins when recording the coverage:

          java.lang.IllegalArgumentException: There is already a child [CLASS] consultants_controller <0>
            with the name consultants_controller in [FILE] consultants_controller.rb 

          I already commented on a related bug report for the project.

          JavaScript

          For our JavaScript tests we use the built in cobertura formatter from jest (`--coverage-reporters=cobertura`), which also doesn't care about unique name attributes:

          grep successCallback tmp/ci_reports/jest/cobertura-coverage.xml
                      <method name="successCallback" hits="0" signature="()V">
                      <method name="successCallback" hits="0" signature="()V">
                      <method name="successCallback" hits="0" signature="()V"> 

          Resulting in this error:

          java.lang.IllegalArgumentException: There is already a child [METHOD] successCallback()V <0>
            with the name successCallback()V in [CLASS] orgs_bulk_status_update.controller.js 

           

          dani added a comment - - edited We run into the same problem with Ruby and JavaScript code coverage. This used to work in the past but started failing when we upgraded the coverage plugin (1.6.0 -> 1.13.0) and deactivated the deprecated code coverage plugin (4.7.0). Ruby We are using the simplecov-cobertura formatter and the coverage report contains two classes with the same name: grep consultants_controller tmp/ci_reports/coverage/coverage.xml < class name= "consultants_controller" filename= "app/controllers/admin/consultants_controller.rb" line-rate= "0.67" complexity= "0" > < class name= "consultants_controller" filename= "app/controllers/consultants_controller.rb" line-rate= "1.0" complexity= "0" > Which causes the following error on Jenkins when recording the coverage: java.lang.IllegalArgumentException: There is already a child [CLASS] consultants_controller <0> with the name consultants_controller in [FILE] consultants_controller.rb I already commented on a related bug report for the project . JavaScript For our JavaScript tests we use the built in cobertura formatter from jest (`--coverage-reporters=cobertura`), which also doesn't care about unique name attributes: grep successCallback tmp/ci_reports/jest/cobertura-coverage.xml             <method name= "successCallback" hits= "0" signature= "()V" >             <method name= "successCallback" hits= "0" signature= "()V" >             <method name= "successCallback" hits= "0" signature= "()V" > Resulting in this error: java.lang.IllegalArgumentException: There is already a child [METHOD] successCallback()V <0> with the name successCallback()V in [CLASS] orgs_bulk_status_update.controller.js  

          Ulli Hafner added a comment -

          This parsing error is quite unfortunate since such code with several lambdas in the same scope is by no means exotic or rare.

           

          It would be helpful if you can report that bug to the coverage tool as well. I would assume that (like in the VM) every lambda has a unique (autogenerated) name in the compiled code.

           

          Ulli Hafner added a comment - This parsing error is quite unfortunate since such code with several lambdas in the same scope is by no means exotic or rare.   It would be helpful if you can report that bug to the coverage tool as well. I would assume that (like in the VM) every lambda has a unique (autogenerated) name in the compiled code.  

          Ulli Hafner added a comment -

          dsager, pila: Can you please attach some small cobertura files that expose these problems? Maybe it makes sense to autogenerate names in such cases (or by flag).

          Ulli Hafner added a comment - dsager , pila : Can you please attach some small cobertura files that expose these problems? Maybe it makes sense to autogenerate names in such cases (or by flag).

          dani added a comment -

          Hi drulli!

          Here's a very simple example, let me know if it's good enough of an example.

          The structure has two classes with an identical name placed in different modules:

          module Foobar
            module Bar
              class MyClass
          
          module Foobar
            module Baz
              class MyClass
          

          coverage.xml

          dani added a comment - Hi drulli ! Here's a very simple example, let me know if it's good enough of an example. The structure has two classes with an identical name placed in different modules: module Foobar module Bar class MyClass module Foobar module Baz class MyClass coverage.xml

          David added a comment - - edited

          Just to note: this also happens in JavaScript if there's an instance (prototype) method and a static method of the same name on a given class. For example,

          function Foo () {}
          
          Foo.prototype.bar = function bar() {}
          Foo.bar = function bar () {}
          
          new Foo().bar()
          Foo.bar() 

          cobertura-coverage-1.xml

          David added a comment - - edited Just to note: this also happens in JavaScript if there's an instance (prototype) method and a static method of the same name on a given class. For example, function Foo () {} Foo.prototype.bar = function bar() {} Foo.bar = function bar () {} new Foo().bar() Foo.bar() cobertura-coverage-1.xml

          Pierre added a comment -

          The function I posted in the description pretty much exactly translates into the Cobertura snippet following it (modulo the exact metrics) when using Squish Coco. Although, in C++, every lambda has a unique type, that type is not accessible by the programmer and is compiler-internal. Hence tools such as Squish Coco can also not really access it which is presumably why they just generate this method name always ending in the same generic "::[lambda]". This whole thing is not so much the Coverage plug-in's fault but rather that of those tools generating the Cobertura files since they do not really implement a well enough disambiguation between different lambdas with the same signature in the same scope. The only unfortunate thing is that this produces hard errors in the Coverage plug-in afterwards.

          For our project, we implemented some workaround by post-processing the Cobertura files on our side before passing them to the Coverage plug-in. This is not the most pretty solution, but it mostly works fine.

          Pierre added a comment - The function I posted in the description pretty much exactly translates into the Cobertura snippet following it (modulo the exact metrics) when using Squish Coco. Although, in C++, every lambda has a unique type, that type is not accessible by the programmer and is compiler-internal. Hence tools such as Squish Coco can also not really access it which is presumably why they just generate this method name always ending in the same generic ":: [lambda] ". This whole thing is not so much the Coverage plug-in's fault but rather that of those tools generating the Cobertura files since they do not really implement a well enough disambiguation between different lambdas with the same signature in the same scope. The only unfortunate thing is that this produces hard errors in the Coverage plug-in afterwards. For our project, we implemented some workaround by post-processing the Cobertura files on our side before passing them to the Coverage plug-in. This is not the most pretty solution, but it mostly works fine.

            drulli Ulli Hafner
            pila Pierre
            Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: