Skip to content
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

[Bug]: Uncovered lines are shown as covered when there are annotations #42605

Open
MaryamZi opened this issue Apr 22, 2024 · 6 comments · May be fixed by #42724
Open

[Bug]: Uncovered lines are shown as covered when there are annotations #42605

MaryamZi opened this issue Apr 22, 2024 · 6 comments · May be fixed by #42724
Assignees
Labels
Team/CompilerFE All issues related to Language implementation and Compiler, this exclude run times. Team/jBallerina All the issues related to BIR, JVM backend code generation and runtime Type/Bug

Comments

@MaryamZi
Copy link
Member

MaryamZi commented Apr 22, 2024

Description

$title. May be related to annotation closures.

Steps to Reproduce

import ballerina/graphql;

service class Profile {
    private final string name;
    private final int age;

    function init(string name, int age) {
        self.name = name;
        self.age = age;
    }

    resource function get name() returns string {
        return self.name;
    }

    resource function get age() returns int {
        return self.age;
    }

    resource function get isAdult() returns boolean {
        return self.age > 21;
    }

    resource function get reviews() returns Review[] {
        return [
            new (1, "review 1"),
            new (2, "review 2")
        ];
    }
}

annotation MyAnnot on parameter, return, class;

@MyAnnot
service class Review {
    int id;
    string content;

    function init(
            @MyAnnot 
                int id, string content) {
        self.id = id;
        self.content = content;
    }

    resource function get id() returns @MyAnnot int {
        return self.id;
    }

    resource function get content() returns string {
        return self.content;
    }
}

service /graphql on new graphql:Listener(9090) {

    resource function get profile() returns Profile {
        return new ("John Doe", 51);
    }
}

Tests

import ballerina/graphql;
import ballerina/test;
       
final graphql:Client cl = check new ("http://localhost:9090/graphql");

@test:Config
function testCallOriginal() returns error? {
    json j = check cl->execute(string `{ profile { name isAdult } }`);
    test:assertEquals(j, {"data":{"profile":{"name":"John Doe", "isAdult":true}}});
}

Screenshot from 2024-04-22 11-43-40

Affected Version(s)

2201.9.0-rc1

@MaryamZi MaryamZi added Type/Bug Team/CompilerFE All issues related to Language implementation and Compiler, this exclude run times. Team/jBallerina All the issues related to BIR, JVM backend code generation and runtime labels Apr 22, 2024
@gabilang gabilang linked a pull request May 9, 2024 that will close this issue
13 tasks
@gabilang
Copy link
Contributor

This issue can be mitigated by removing the position information of the annotation desugered functions from the line number table. This will ignore the lines related to annotations from the code coverage. If we do so, annotation related (annotation desugared functions) lines will be excluded from the stack traces as well.
eg.,

1   annotation ZeroDiffAnnot zeroDivAnnot on function;
2
3   function zeroDiv(int n) returns boolean {
4     return n / 0 == 0;
5   }
6
7   @zeroDivAnnot {
8      value: "ZeroDiv",
9      out: zeroDiv(10)
10   }
11   function foo(int n) returns int {
12      return n;
13   }
error: {ballerina}DivisionByZero {"message":" / by zero"}
        at gabilan.test_project.0:zeroDiv(main.bal:4)
           gabilan.test__project.0:$annot_func$_0(main.bal:9)

If we remove the line numbers of annotation desugared functions from the line number table, the stack trace will not contain the line gabilan.test_project.0:$annot_func$_0(main.bal:9).
Since, the annotation related bytecode instructions are used during the test running, the jacoco will detect the lines related to those bytecode instructions as partially/fully covered.

@gabilang
Copy link
Contributor

It seems without removing the positions related to the annotations from the line number table, we can't avoid the annotations from the code coverage. Anyway the code coverage of actual code lines which are need to be covered by the user's test cases are depend on the availability of the tests.
So, IMO it's okay to show the annotation related lines as covered in the coverage report. @warunalakshitha @MaryamZi WDYT?

@MaryamZi
Copy link
Member Author

How do we decide if it is covered? For example, with the original example, a Review object is not even created, but relevant code lines are shown as covered, which is not correct IMO.

@gabilang
Copy link
Contributor

gabilang commented May 20, 2024

How do we decide if it is covered? For example, with the original example, a Review object is not even created, but relevant code lines are shown as covered, which is not correct IMO.

Agree. But the following case also panics without the function foo() is being called inside the main.

1   annotation ZeroDiffAnnot zeroDivAnnot on function;
2
3   function zeroDiv(int n) returns boolean {
4     return n / 0 == 0;
5   }
6
7   @zeroDivAnnot {
8      value: "ZeroDiv",
9      out: zeroDiv(10)
10   }
11   function foo(int n) returns int {
12      return n;
13   }

This is happening due to the annotation desugared are getting called during the initialization phase.

It may not necessary to consider annotations for code coverage, since they usually provide structured metadata about a particular construct. So we can omit annotation related lines from code coverage.
But what about removing the entry related to the line-number 9 of the above example from the stack trace?

@gabilang
Copy link
Contributor

Spec says, An annotation applied to a module-level declaration is evaluated when the module is initialized. An annotation applied to a service constructor is evaluated when the service constructor is evaluated. An annotation occurring within a type descriptor is evaluated when the type descriptor is resolved.

Since the annotations related lines of module-level declarations are evaluated at module initialization, the bytecode instructions related those lines are executed during the test run, even there are no added tests. So jacoco marks those annotation related lines are covered.

@gabilang
Copy link
Contributor

There are lines showed as covered in the following case without having relevant added tests.
code-cov-on-init-start-stop
This is because these functions are called at module init, start and stop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Team/CompilerFE All issues related to Language implementation and Compiler, this exclude run times. Team/jBallerina All the issues related to BIR, JVM backend code generation and runtime Type/Bug
Projects
Status: On Hold
Development

Successfully merging a pull request may close this issue.

2 participants