Skip to content

Commit ca72aae

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

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-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: 64 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,15 @@ 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+
updateSpongeProperties(celCoverageIndex.generateCoverageReport());
166+
}
147167
}
148168

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

0 commit comments

Comments
 (0)