Skip to content

Commit 09b6d2e

Browse files
l46kokcopybara-github
authored andcommitted
Refactor test runner to accept required descriptors at the callsite, introduce BindingTransformer
PiperOrigin-RevId: 888890758
1 parent 690d082 commit 09b6d2e

File tree

9 files changed

+272
-69
lines changed

9 files changed

+272
-69
lines changed

conformance/src/test/java/dev/cel/conformance/ConformanceTest.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
import static com.google.common.truth.Truth.assertThat;
1818
import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
19-
import static dev.cel.testing.utils.ExprValueUtils.DEFAULT_EXTENSION_REGISTRY;
20-
import static dev.cel.testing.utils.ExprValueUtils.DEFAULT_TYPE_REGISTRY;
2119
import static dev.cel.testing.utils.ExprValueUtils.fromValue;
2220
import static dev.cel.testing.utils.ExprValueUtils.toExprValue;
2321

@@ -29,6 +27,8 @@
2927
import com.google.common.base.Preconditions;
3028
import com.google.common.collect.ImmutableList;
3129
import com.google.common.collect.ImmutableMap;
30+
import com.google.protobuf.ExtensionRegistry;
31+
import com.google.protobuf.TypeRegistry;
3232
import dev.cel.checker.CelChecker;
3333
import dev.cel.common.CelContainer;
3434
import dev.cel.common.CelOptions;
@@ -84,6 +84,21 @@ public final class ConformanceTest extends Statement {
8484
CelExtensions.strings(),
8585
CelOptionalLibrary.INSTANCE);
8686

87+
static final TypeRegistry CONFORMANCE_TYPE_REGISTRY =
88+
TypeRegistry.newBuilder()
89+
.add(dev.cel.expr.conformance.proto2.TestAllTypes.getDescriptor())
90+
.add(dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor())
91+
.build();
92+
93+
static final ExtensionRegistry CONFORMANCE_EXTENSION_REGISTRY =
94+
createConformanceExtensionRegistry();
95+
96+
private static ExtensionRegistry createConformanceExtensionRegistry() {
97+
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
98+
dev.cel.expr.conformance.proto2.TestAllTypesExtensions.registerAllExtensions(extensionRegistry);
99+
return extensionRegistry;
100+
}
101+
87102
private static final CelParser PARSER_WITH_MACROS =
88103
CelParserFactory.standardCelParserBuilder()
89104
.setOptions(OPTIONS)
@@ -106,7 +121,7 @@ private static CelChecker getChecker(SimpleTest test) throws Exception {
106121
ImmutableList.Builder<Decl> decls =
107122
ImmutableList.builderWithExpectedSize(test.getTypeEnvCount());
108123
for (dev.cel.expr.Decl decl : test.getTypeEnvList()) {
109-
decls.add(Decl.parseFrom(decl.toByteArray(), DEFAULT_EXTENSION_REGISTRY));
124+
decls.add(Decl.parseFrom(decl.toByteArray(), CONFORMANCE_EXTENSION_REGISTRY));
110125
}
111126
return CelCompilerFactory.standardCelCheckerBuilder()
112127
.setOptions(OPTIONS)
@@ -127,7 +142,7 @@ private static CelRuntime getRuntime(SimpleTest test, boolean usePlanner) {
127142
// CEL-Internal-2
128143
.setOptions(OPTIONS)
129144
.addLibraries(CANONICAL_RUNTIME_EXTENSIONS)
130-
.setExtensionRegistry(DEFAULT_EXTENSION_REGISTRY)
145+
.setExtensionRegistry(CONFORMANCE_EXTENSION_REGISTRY)
131146
.addMessageTypes(dev.cel.expr.conformance.proto2.TestAllTypes.getDescriptor())
132147
.addMessageTypes(dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor())
133148
.addFileTypes(dev.cel.expr.conformance.proto2.TestAllTypesExtensions.getDescriptor());
@@ -151,7 +166,8 @@ private static ImmutableMap<String, Object> getBindings(SimpleTest test) throws
151166
private static Object fromExprValue(ExprValue value) throws Exception {
152167
switch (value.getKindCase()) {
153168
case VALUE:
154-
return fromValue(value.getValue());
169+
return fromValue(
170+
value.getValue(), CONFORMANCE_TYPE_REGISTRY, CONFORMANCE_EXTENSION_REGISTRY);
155171
default:
156172
throw new IllegalArgumentException(
157173
String.format("Unexpected binding value kind: %s", value.getKindCase()));
@@ -224,7 +240,7 @@ public void evaluate() throws Throwable {
224240
assertThat(result)
225241
.ignoringRepeatedFieldOrderOfFieldDescriptors(
226242
MapValue.getDescriptor().findFieldByName("entries"))
227-
.unpackingAnyUsing(DEFAULT_TYPE_REGISTRY, DEFAULT_EXTENSION_REGISTRY)
243+
.unpackingAnyUsing(CONFORMANCE_TYPE_REGISTRY, CONFORMANCE_EXTENSION_REGISTRY)
228244
.isEqualTo(ExprValue.newBuilder().setValue(test.getValue()).build());
229245
break;
230246
case EVAL_ERROR:
@@ -237,7 +253,7 @@ public void evaluate() throws Throwable {
237253
assertThat(result)
238254
.ignoringRepeatedFieldOrderOfFieldDescriptors(
239255
MapValue.getDescriptor().findFieldByName("entries"))
240-
.unpackingAnyUsing(DEFAULT_TYPE_REGISTRY, DEFAULT_EXTENSION_REGISTRY)
256+
.unpackingAnyUsing(CONFORMANCE_TYPE_REGISTRY, CONFORMANCE_EXTENSION_REGISTRY)
241257
.isEqualTo(ExprValue.newBuilder().setValue(test.getTypedResult().getResult()).build());
242258
assertThat(resultType).isEqualTo(test.getTypedResult().getDeducedType());
243259
break;

conformance/src/test/java/dev/cel/conformance/ConformanceTestRunner.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
package dev.cel.conformance;
1616

17-
import static dev.cel.testing.utils.ExprValueUtils.DEFAULT_EXTENSION_REGISTRY;
18-
import static dev.cel.testing.utils.ExprValueUtils.DEFAULT_TYPE_REGISTRY;
17+
import static dev.cel.conformance.ConformanceTest.CONFORMANCE_EXTENSION_REGISTRY;
1918

2019
import com.google.common.base.Preconditions;
2120
import com.google.common.base.Splitter;
@@ -50,14 +49,16 @@ private static ImmutableSortedMap<String, SimpleTestFile> loadTestFiles() {
5049
SPLITTER.splitToList(System.getProperty("dev.cel.conformance.ConformanceTests.tests"));
5150
try {
5251
TextFormat.Parser parser =
53-
TextFormat.Parser.newBuilder().setTypeRegistry(DEFAULT_TYPE_REGISTRY).build();
52+
TextFormat.Parser.newBuilder()
53+
.setTypeRegistry(ConformanceTest.CONFORMANCE_TYPE_REGISTRY)
54+
.build();
5455
ImmutableSortedMap.Builder<String, SimpleTestFile> testFiles =
5556
ImmutableSortedMap.naturalOrder();
5657
for (String testPath : testPaths) {
5758
SimpleTestFile.Builder fileBuilder = SimpleTestFile.newBuilder();
5859
try (BufferedReader input =
5960
Files.newBufferedReader(Paths.get(testPath), StandardCharsets.UTF_8)) {
60-
parser.merge(input, DEFAULT_EXTENSION_REGISTRY, fileBuilder);
61+
parser.merge(input, CONFORMANCE_EXTENSION_REGISTRY, fileBuilder);
6162
}
6263
SimpleTestFile testFile = fileBuilder.build();
6364
testFiles.put(testFile.getName(), testFile);

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ java_library(
9292
"//bundle:environment",
9393
"//bundle:environment_yaml_parser",
9494
"//common:cel_ast",
95+
"//common:cel_descriptor_util",
9596
"//common:compiler_common",
9697
"//common:options",
9798
"//common:proto_ast",
@@ -134,6 +135,7 @@ java_library(
134135
":cel_test_suite",
135136
":cel_test_suite_exception",
136137
"//common:compiler_common",
138+
"//common/annotations",
137139
"//common/formats:file_source",
138140
"//common/formats:parser_context",
139141
"//common/formats:yaml_helper",
@@ -163,10 +165,14 @@ java_library(
163165
":result_matcher",
164166
"//:auto_value",
165167
"//bundle:cel",
168+
"//common:cel_descriptor_util",
166169
"//common:options",
167170
"//policy:parser",
168171
"//runtime",
172+
"//testing/testrunner:proto_descriptor_utils",
173+
"@maven//:com_google_errorprone_error_prone_annotations",
169174
"@maven//:com_google_guava_guava",
175+
"@maven//:com_google_protobuf_protobuf_java",
170176
],
171177
)
172178

@@ -223,6 +229,7 @@ java_library(
223229
":cel_test_suite",
224230
":cel_test_suite_exception",
225231
":registry_utils",
232+
"//common/annotations",
226233
"@cel_spec//proto/cel/expr:expr_java_proto",
227234
"@cel_spec//proto/cel/expr/conformance/test:suite_java_proto",
228235
"@maven//:com_google_guava_guava",

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,23 @@
1414
package dev.cel.testing.testrunner;
1515

1616
import com.google.auto.value.AutoValue;
17+
import com.google.auto.value.extension.memoized.Memoized;
1718
import com.google.common.collect.ImmutableMap;
19+
import com.google.common.collect.ImmutableSet;
20+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
21+
import com.google.protobuf.Descriptors.Descriptor;
22+
import com.google.protobuf.Descriptors.FileDescriptor;
23+
import com.google.protobuf.ExtensionRegistry;
24+
import com.google.protobuf.TypeRegistry;
1825
import dev.cel.bundle.Cel;
1926
import dev.cel.bundle.CelFactory;
27+
import dev.cel.common.CelDescriptorUtil;
2028
import dev.cel.common.CelOptions;
2129
import dev.cel.policy.CelPolicyParser;
2230
import dev.cel.runtime.CelLateFunctionBindings;
31+
import dev.cel.testing.utils.ProtoDescriptorUtils;
32+
import java.io.IOException;
33+
import java.util.Arrays;
2334
import java.util.Map;
2435
import java.util.Optional;
2536

@@ -63,6 +74,19 @@ public abstract class CelTestContext {
6374
*/
6475
public abstract Optional<CelLateFunctionBindings> celLateFunctionBindings();
6576

77+
/** Interface for transforming bindings before evaluation. */
78+
@FunctionalInterface
79+
public interface BindingTransformer {
80+
ImmutableMap<String, Object> transform(ImmutableMap<String, Object> bindings) throws Exception;
81+
}
82+
83+
/**
84+
* The binding transformer for the CEL test.
85+
*
86+
* <p>This transformer is used to transform the bindings before evaluation.
87+
*/
88+
public abstract Optional<BindingTransformer> bindingTransformer();
89+
6690
/**
6791
* The variable bindings for the CEL test.
6892
*
@@ -99,6 +123,34 @@ public abstract class CelTestContext {
99123
*/
100124
public abstract Optional<String> fileDescriptorSetPath();
101125

126+
abstract ImmutableSet<FileDescriptor> fileTypes();
127+
128+
@Memoized
129+
public Optional<TypeRegistry> typeRegistry() {
130+
if (fileTypes().isEmpty() && !fileDescriptorSetPath().isPresent()) {
131+
return Optional.empty();
132+
}
133+
TypeRegistry.Builder builder = TypeRegistry.newBuilder();
134+
if (!fileTypes().isEmpty()) {
135+
builder.add(
136+
CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(fileTypes())
137+
.messageTypeDescriptors());
138+
}
139+
if (fileDescriptorSetPath().isPresent()) {
140+
try {
141+
builder.add(
142+
ProtoDescriptorUtils.getAllDescriptorsFromJvm(fileDescriptorSetPath().get())
143+
.messageTypeDescriptors());
144+
} catch (IOException e) {
145+
throw new IllegalStateException(
146+
"Failed to load descriptors from path: " + fileDescriptorSetPath().get(), e);
147+
}
148+
}
149+
return Optional.of(builder.build());
150+
}
151+
152+
public abstract Optional<ExtensionRegistry> extensionRegistry();
153+
102154
/** Returns a builder for {@link CelTestContext} with the current instance's values. */
103155
public abstract Builder toBuilder();
104156

@@ -123,6 +175,8 @@ public abstract static class Builder {
123175
public abstract Builder setCelLateFunctionBindings(
124176
CelLateFunctionBindings celLateFunctionBindings);
125177

178+
public abstract Builder setBindingTransformer(BindingTransformer bindingTransformer);
179+
126180
public abstract Builder setVariableBindings(Map<String, Object> variableBindings);
127181

128182
public abstract Builder setResultMatcher(ResultMatcher resultMatcher);
@@ -133,6 +187,34 @@ public abstract Builder setCelLateFunctionBindings(
133187

134188
public abstract Builder setFileDescriptorSetPath(String fileDescriptorSetPath);
135189

190+
abstract ImmutableSet.Builder<FileDescriptor> fileTypesBuilder();
191+
192+
@CanIgnoreReturnValue
193+
public Builder addMessageTypes(Descriptor... descriptors) {
194+
return addMessageTypes(Arrays.asList(descriptors));
195+
}
196+
197+
@CanIgnoreReturnValue
198+
public Builder addMessageTypes(Iterable<Descriptor> descriptors) {
199+
for (Descriptor descriptor : descriptors) {
200+
addFileTypes(descriptor.getFile());
201+
}
202+
return this;
203+
}
204+
205+
@CanIgnoreReturnValue
206+
public Builder addFileTypes(FileDescriptor... fileDescriptors) {
207+
return addFileTypes(Arrays.asList(fileDescriptors));
208+
}
209+
210+
@CanIgnoreReturnValue
211+
public Builder addFileTypes(Iterable<FileDescriptor> fileDescriptors) {
212+
fileTypesBuilder().addAll(fileDescriptors);
213+
return this;
214+
}
215+
216+
public abstract Builder setExtensionRegistry(ExtensionRegistry extensionRegistry);
217+
136218
public abstract CelTestContext build();
137219
}
138220
}

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

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.protobuf.TextFormat;
2323
import com.google.protobuf.TextFormat.ParseException;
2424
import com.google.protobuf.TypeRegistry;
25+
import dev.cel.common.annotations.Internal;
2526
import dev.cel.expr.conformance.test.InputValue;
2627
import dev.cel.expr.conformance.test.TestCase;
2728
import dev.cel.expr.conformance.test.TestSection;
@@ -35,23 +36,40 @@
3536
/**
3637
* CelTestSuiteTextProtoParser intakes a textproto document that describes the structure of a CEL
3738
* test suite, parses it then creates a {@link CelTestSuite}.
39+
*
40+
* <p>CEL Library Internals. Do Not Use.
3841
*/
39-
final class CelTestSuiteTextProtoParser {
42+
@Internal
43+
public final class CelTestSuiteTextProtoParser {
4044

4145
/** Creates a new instance of {@link CelTestSuiteTextProtoParser}. */
42-
static CelTestSuiteTextProtoParser newInstance() {
46+
public static CelTestSuiteTextProtoParser newInstance() {
4347
return new CelTestSuiteTextProtoParser();
4448
}
4549

46-
CelTestSuite parse(String textProto) throws IOException, CelTestSuiteException {
47-
TestSuite testSuite = parseTestSuite(textProto);
50+
public CelTestSuite parse(String textProto) throws IOException, CelTestSuiteException {
51+
return parse(
52+
textProto, TypeRegistry.getEmptyTypeRegistry(), ExtensionRegistry.getEmptyRegistry());
53+
}
54+
55+
public CelTestSuite parse(String textProto, TypeRegistry customTypeRegistry)
56+
throws IOException, CelTestSuiteException {
57+
return parse(textProto, customTypeRegistry, ExtensionRegistry.getEmptyRegistry());
58+
}
59+
60+
public CelTestSuite parse(
61+
String textProto, TypeRegistry customTypeRegistry, ExtensionRegistry customExtensionRegistry)
62+
throws IOException, CelTestSuiteException {
63+
TestSuite testSuite = parseTestSuite(textProto, customTypeRegistry, customExtensionRegistry);
4864
return parseCelTestSuite(testSuite);
4965
}
5066

51-
private TestSuite parseTestSuite(String textProto) throws IOException {
67+
private TestSuite parseTestSuite(
68+
String textProto, TypeRegistry customTypeRegistry, ExtensionRegistry customExtensionRegistry)
69+
throws IOException {
5270
String fileDescriptorSetPath = System.getProperty("file_descriptor_set_path");
53-
TypeRegistry typeRegistry = TypeRegistry.getEmptyTypeRegistry();
54-
ExtensionRegistry extensionRegistry = ExtensionRegistry.getEmptyRegistry();
71+
TypeRegistry typeRegistry = customTypeRegistry;
72+
ExtensionRegistry extensionRegistry = customExtensionRegistry;
5573
if (fileDescriptorSetPath != null) {
5674
extensionRegistry = RegistryUtils.getExtensionRegistry(fileDescriptorSetPath);
5775
typeRegistry = RegistryUtils.getTypeRegistry(fileDescriptorSetPath);

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.google.common.collect.ImmutableMap;
2626
import com.google.common.collect.ImmutableSet;
2727
import dev.cel.common.CelIssue;
28+
import dev.cel.common.annotations.Internal;
2829
import dev.cel.common.formats.CelFileSource;
2930
import dev.cel.common.formats.ParserContext;
3031
import dev.cel.common.formats.YamlHelper.YamlNodeType;
@@ -43,15 +44,18 @@
4344
/**
4445
* CelTestSuiteYamlParser intakes a YAML document that describes the structure of a CEL test suite,
4546
* parses it then creates a {@link CelTestSuite}.
47+
*
48+
* <p>CEL Library Internals. Do Not Use.
4649
*/
47-
final class CelTestSuiteYamlParser {
50+
@Internal
51+
public final class CelTestSuiteYamlParser {
4852

4953
/** Creates a new instance of {@link CelTestSuiteYamlParser}. */
50-
static CelTestSuiteYamlParser newInstance() {
54+
public static CelTestSuiteYamlParser newInstance() {
5155
return new CelTestSuiteYamlParser();
5256
}
5357

54-
CelTestSuite parse(String celTestSuiteYamlContent) throws CelTestSuiteException {
58+
public CelTestSuite parse(String celTestSuiteYamlContent) throws CelTestSuiteException {
5559
return parseYaml(celTestSuiteYamlContent, "<input>");
5660
}
5761

@@ -110,6 +114,7 @@ private CelTestSuite.Builder parseTestSuite(ParserContext<Node> ctx, Node node)
110114
case "description":
111115
builder.setDescription(newString(ctx, valueNode));
112116
break;
117+
case "section":
113118
case "sections":
114119
builder.setSections(parseSections(ctx, valueNode));
115120
break;

0 commit comments

Comments
 (0)