Skip to content

Commit 745541b

Browse files
ChinmayMadeshicopybara-github
authored andcommitted
Enable coverage collection via the runner library for a single test.
PiperOrigin-RevId: 813092582
1 parent 668d3e5 commit 745541b

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

testing/src/main/java/dev/cel/testing/testrunner/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ java_library(
9696
"//common:options",
9797
"//common:proto_ast",
9898
"//common/internal:default_instance_message_factory",
99+
"//java/com/google/testing/junit/runner/util",
99100
"//policy",
100101
"//policy:compiler_factory",
101102
"//policy:parser",

testing/src/main/java/dev/cel/testing/testrunner/TestRunnerLibrary.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.google.protobuf.ExtensionRegistry;
3232
import com.google.protobuf.Message;
3333
import com.google.protobuf.TextFormat;
34+
import com.google.testing.junit.runner.util.TestPropertyExporter;
3435
import dev.cel.bundle.Cel;
3536
import dev.cel.bundle.CelEnvironment;
3637
import dev.cel.bundle.CelEnvironment.ExtensionConfig;
@@ -66,6 +67,16 @@ public final class TestRunnerLibrary {
6667

6768
private static final Logger logger = Logger.getLogger(TestRunnerLibrary.class.getName());
6869

70+
private static final String ATTR_CEL_EXPR = "Cel Expr";
71+
private static final String ATTR_CEL_COVERAGE = "Cel Coverage";
72+
private static final String ATTR_AST_NODE_COVERAGE = "Ast Node Coverage";
73+
private static final String ATTR_INTERESTING_UNENCOUNTERED_NODES =
74+
"Interesting Unencountered Nodes";
75+
private static final String ATTR_AST_BRANCH_COVERAGE = "Ast Branch Coverage";
76+
private static final String ATTR_INTERESTING_UNENCOUNTERED_BRANCH_PATHS =
77+
"Interesting Unencountered Branch Paths";
78+
private static final String ATTR_CEL_TEST_COVERAGE_GRAPH_URL = "Cel Test Coverage Graph URL";
79+
6980
/**
7081
* Run the assertions for a given raw/checked expression test case.
7182
*
@@ -144,6 +155,16 @@ static void evaluateTestCase(
144155
celCoverageIndex.init(ast);
145156
}
146157
evaluate(ast, testCase, celTestContext, celCoverageIndex);
158+
159+
// For programmatic tests, if coverage is not enabled via the build macro, update the Sponge
160+
// properties with the coverage report.
161+
// This flag does not exist when the test is run via direct invocation of {@link
162+
// TestRunnerLibrary#runTest}
163+
String isCoverageEnabled = System.getProperty("is_coverage_enabled");
164+
if (isCoverageEnabled == null && celCoverageIndex != null) {
165+
CelCoverageIndex.CoverageReport report = celCoverageIndex.generateCoverageReport();
166+
updateSpongeProperties(report);
167+
}
147168
}
148169

149170
private static CelAbstractSyntaxTree readAstFromCheckedExpression(
@@ -403,4 +424,48 @@ private static Object getValueFromBinding(Object value, CelTestContext celTestCo
403424
}
404425
return value;
405426
}
427+
428+
/**
429+
* Updates Sponge properties with the provided coverage report.
430+
*
431+
* <p>This method is called when {@link TestRunnerLibrary#runTest} is invoked directly to export
432+
* coverage data.
433+
*/
434+
private static void updateSpongeProperties(CelCoverageIndex.CoverageReport report) {
435+
TestPropertyExporter exporter = TestPropertyExporter.INSTANCE;
436+
if (report.nodes() == 0) {
437+
exporter.exportProperty(ATTR_CEL_COVERAGE, "No coverage stats found");
438+
} else {
439+
// CEL expression
440+
exporter.exportProperty(ATTR_CEL_EXPR, report.celExpression());
441+
// Node coverage
442+
double nodeCoverage = (double) report.coveredNodes() / (double) report.nodes() * 100.0;
443+
String nodeCoverageString =
444+
String.format(
445+
"%.2f%% (%d out of %d nodes covered)",
446+
nodeCoverage, report.coveredNodes(), report.nodes());
447+
exporter.exportProperty(ATTR_AST_NODE_COVERAGE, nodeCoverageString);
448+
if (!report.unencounteredNodes().isEmpty()) {
449+
exporter.exportProperty(
450+
ATTR_INTERESTING_UNENCOUNTERED_NODES, String.join("\n", report.unencounteredNodes()));
451+
}
452+
// Branch coverage
453+
double branchCoverage = 0.0;
454+
if (report.branches() > 0) {
455+
branchCoverage =
456+
(double) report.coveredBooleanOutcomes() / (double) report.branches() * 100.0;
457+
}
458+
String branchCoverageString =
459+
String.format(
460+
"%.2f%% (%d out of %d branch outcomes covered)",
461+
branchCoverage, report.coveredBooleanOutcomes(), report.branches());
462+
exporter.exportProperty(ATTR_AST_BRANCH_COVERAGE, branchCoverageString);
463+
if (!report.unencounteredBranches().isEmpty()) {
464+
exporter.exportProperty(
465+
ATTR_INTERESTING_UNENCOUNTERED_BRANCH_PATHS,
466+
String.join("\n", report.unencounteredBranches()));
467+
}
468+
exporter.exportProperty(ATTR_CEL_TEST_COVERAGE_GRAPH_URL, report.graphUrl());
469+
}
470+
}
406471
}

0 commit comments

Comments
 (0)