diff --git a/common/internal/BUILD.bazel b/common/internal/BUILD.bazel index 0a07e0d63..781566713 100644 --- a/common/internal/BUILD.bazel +++ b/common/internal/BUILD.bazel @@ -128,11 +128,6 @@ cel_android_library( exports = ["//common/src/main/java/dev/cel/common/internal:internal_android"], ) -java_library( - name = "proto_java_qualified_names", - exports = ["//common/src/main/java/dev/cel/common/internal:proto_java_qualified_names"], -) - java_library( name = "proto_time_utils", exports = ["//common/src/main/java/dev/cel/common/internal:proto_time_utils"], diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index 912b4de4b..6b470d98c 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -153,7 +153,6 @@ java_library( tags = [ ], deps = [ - ":proto_java_qualified_names", ":reflection_util", "//common/annotations", "@maven//:com_google_guava_guava", @@ -396,18 +395,6 @@ java_library( ], ) -java_library( - name = "proto_java_qualified_names", - srcs = ["ProtoJavaQualifiedNames.java"], - tags = [ - ], - deps = [ - "//common/annotations", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", - ], -) - java_library( name = "reflection_util", srcs = ["ReflectionUtil.java"], diff --git a/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java b/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java index fcb0e7056..163d0273e 100644 --- a/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java +++ b/common/src/main/java/dev/cel/common/internal/DefaultInstanceMessageFactory.java @@ -15,6 +15,7 @@ package dev.cel.common.internal; import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.GeneratorNames; import com.google.protobuf.Message; import com.google.protobuf.MessageLite; import dev.cel.common.annotations.Internal; @@ -45,9 +46,7 @@ public static DefaultInstanceMessageFactory getInstance() { public Optional getPrototype(Descriptor descriptor) { MessageLite defaultInstance = DefaultInstanceMessageLiteFactory.getInstance() - .getPrototype( - descriptor.getFullName(), - ProtoJavaQualifiedNames.getFullyQualifiedJavaClassName(descriptor)) + .getPrototype(descriptor.getFullName(), GeneratorNames.getBytecodeClassName(descriptor)) .orElse(null); if (defaultInstance == null) { return Optional.empty(); diff --git a/common/src/main/java/dev/cel/common/internal/ProtoJavaQualifiedNames.java b/common/src/main/java/dev/cel/common/internal/ProtoJavaQualifiedNames.java deleted file mode 100644 index f27181a50..000000000 --- a/common/src/main/java/dev/cel/common/internal/ProtoJavaQualifiedNames.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2025 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dev.cel.common.internal; - -import com.google.protobuf.Descriptors.Descriptor; -import com.google.protobuf.Descriptors.FileDescriptor; -import com.google.protobuf.GeneratorNames; -import dev.cel.common.annotations.Internal; - -/** - * Helper class for constructing a fully qualified Java class name from a protobuf descriptor. - * - *

CEL Library Internals. Do Not Use. - */ -@Internal -public final class ProtoJavaQualifiedNames { - /** - * Retrieves the full Java class name from the given descriptor - * - * @return fully qualified class name. - *

Example 1: dev.cel.expr.Value - *

Example 2: com.google.rpc.context.AttributeContext$Resource (Nested classes) - *

Example 3: com.google.api.expr.cel.internal.testdata$SingleFileProto$SingleFile$Path - * (Nested class with java multiple files disabled) - */ - public static String getFullyQualifiedJavaClassName(Descriptor descriptor) { - return GeneratorNames.getBytecodeClassName(descriptor); - } - - /** - * Gets the java package name from the descriptor. See - * https://developers.google.com/protocol-buffers/docs/reference/java-generated#package for rules - * on package name generation - */ - public static String getJavaPackageName(FileDescriptor fileDescriptor) { - return GeneratorNames.getFileJavaPackage(fileDescriptor.toProto()); - } - - private ProtoJavaQualifiedNames() {} -} diff --git a/protobuf/src/main/java/dev/cel/protobuf/BUILD.bazel b/protobuf/src/main/java/dev/cel/protobuf/BUILD.bazel index 6e7b473eb..b2dac98e7 100644 --- a/protobuf/src/main/java/dev/cel/protobuf/BUILD.bazel +++ b/protobuf/src/main/java/dev/cel/protobuf/BUILD.bazel @@ -21,7 +21,6 @@ java_binary( ":java_file_generator", ":proto_descriptor_collector", "//common:cel_descriptor_util", - "//common/internal:proto_java_qualified_names", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:info_picocli_picocli", @@ -50,7 +49,6 @@ java_library( ":cel_lite_descriptor", ":debug_printer", ":lite_descriptor_codegen_metadata", - "//common/internal:proto_java_qualified_names", "//common/internal:well_known_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", diff --git a/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptorGenerator.java b/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptorGenerator.java index 276dd7f91..8c4eaea1c 100644 --- a/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptorGenerator.java +++ b/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptorGenerator.java @@ -23,8 +23,8 @@ import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.GeneratorNames; import dev.cel.common.CelDescriptorUtil; -import dev.cel.common.internal.ProtoJavaQualifiedNames; import dev.cel.protobuf.JavaFileGenerator.GeneratedClass; import dev.cel.protobuf.JavaFileGenerator.JavaFileGeneratorOption; import java.io.File; @@ -117,7 +117,7 @@ public Integer call() throws Exception { private ImmutableList codegenCelLiteDescriptors( FileDescriptor targetFileDescriptor) throws Exception { - String javaPackageName = ProtoJavaQualifiedNames.getJavaPackageName(targetFileDescriptor); + String javaPackageName = GeneratorNames.getFileJavaPackage(targetFileDescriptor.toProto()); String javaClassName; List descriptors = targetFileDescriptor.getMessageTypes(); diff --git a/protobuf/src/main/java/dev/cel/protobuf/ProtoDescriptorCollector.java b/protobuf/src/main/java/dev/cel/protobuf/ProtoDescriptorCollector.java index 0031fe6a6..c2fe20557 100644 --- a/protobuf/src/main/java/dev/cel/protobuf/ProtoDescriptorCollector.java +++ b/protobuf/src/main/java/dev/cel/protobuf/ProtoDescriptorCollector.java @@ -22,7 +22,7 @@ import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor.JavaType; import com.google.protobuf.Descriptors.FileDescriptor; -import dev.cel.common.internal.ProtoJavaQualifiedNames; +import com.google.protobuf.GeneratorNames; import dev.cel.common.internal.WellKnownProto; import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor; import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor.EncodingType; @@ -93,8 +93,7 @@ ImmutableList collectCodegenMetadata(Descriptor d // Maps are resolved as an actual Java map, and doesn't have a MessageLite.Builder associated. if (!messageDescriptor.getOptions().getMapEntry()) { String sanitizedJavaClassName = - ProtoJavaQualifiedNames.getFullyQualifiedJavaClassName(messageDescriptor) - .replace('$', '.'); + GeneratorNames.getBytecodeClassName(messageDescriptor).replace('$', '.'); descriptorCodegenBuilder.setJavaClassName(sanitizedJavaClassName); } diff --git a/testing/BUILD.bazel b/testing/BUILD.bazel index b9e68f003..cc389fed1 100644 --- a/testing/BUILD.bazel +++ b/testing/BUILD.bazel @@ -45,3 +45,8 @@ java_library( name = "expr_value_utils", exports = ["//testing/src/main/java/dev/cel/testing/utils:expr_value_utils"], ) + +java_library( + name = "proto_descriptor_utils", + exports = ["//testing/src/main/java/dev/cel/testing/utils:proto_descriptor_utils"], +) diff --git a/testing/src/main/java/dev/cel/testing/testrunner/BUILD.bazel b/testing/src/main/java/dev/cel/testing/testrunner/BUILD.bazel index 5af0665f9..d0fed9bea 100644 --- a/testing/src/main/java/dev/cel/testing/testrunner/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/testrunner/BUILD.bazel @@ -93,10 +93,10 @@ java_library( "//bundle:environment_yaml_parser", "//common:cel_ast", "//common:cel_descriptor_util", + "//common:cel_descriptors", "//common:compiler_common", "//common:options", "//common:proto_ast", - "//common/internal:default_instance_message_factory", "//policy", "//policy:compiler_factory", "//policy:parser", @@ -104,7 +104,6 @@ java_library( "//policy:validation_exception", "//runtime", "//testing:expr_value_utils", - "//testing/testrunner:proto_descriptor_utils", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -166,10 +165,11 @@ java_library( "//:auto_value", "//bundle:cel", "//common:cel_descriptor_util", + "//common:cel_descriptors", "//common:options", "//policy:parser", "//runtime", - "//testing/testrunner:proto_descriptor_utils", + "//testing:proto_descriptor_utils", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -182,8 +182,7 @@ java_library( tags = [ ], deps = [ - "//common/internal:default_instance_message_factory", - "//testing/testrunner:proto_descriptor_utils", + "//common:cel_descriptors", "@maven//:com_google_protobuf_protobuf_java", ], ) @@ -212,8 +211,10 @@ java_library( "//:java_truth", "//bundle:cel", "//common:cel_ast", + "//common:cel_descriptors", "//runtime", "//testing:expr_value_utils", + "//testing:proto_descriptor_utils", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_extensions_truth_proto_extension", @@ -229,7 +230,9 @@ java_library( ":cel_test_suite", ":cel_test_suite_exception", ":registry_utils", + "//common:cel_descriptors", "//common/annotations", + "//testing:proto_descriptor_utils", "@cel_spec//proto/cel/expr:expr_java_proto", "@cel_spec//proto/cel/expr/conformance/test:suite_java_proto", "@maven//:com_google_guava_guava", diff --git a/testing/src/main/java/dev/cel/testing/testrunner/CelTestContext.java b/testing/src/main/java/dev/cel/testing/testrunner/CelTestContext.java index 5635b6152..1be0bab25 100644 --- a/testing/src/main/java/dev/cel/testing/testrunner/CelTestContext.java +++ b/testing/src/main/java/dev/cel/testing/testrunner/CelTestContext.java @@ -25,6 +25,7 @@ import dev.cel.bundle.Cel; import dev.cel.bundle.CelFactory; import dev.cel.common.CelDescriptorUtil; +import dev.cel.common.CelDescriptors; import dev.cel.common.CelOptions; import dev.cel.policy.CelPolicyParser; import dev.cel.runtime.CelLateFunctionBindings; @@ -125,6 +126,20 @@ public interface BindingTransformer { abstract ImmutableSet fileTypes(); + @Memoized + public Optional celDescriptors() { + if (fileDescriptorSetPath().isPresent()) { + try { + return Optional.of( + ProtoDescriptorUtils.getDescriptorsFromFile(fileDescriptorSetPath().get())); + } catch (IOException e) { + throw new IllegalStateException( + "Failed to load descriptors from path: " + fileDescriptorSetPath().get(), e); + } + } + return Optional.empty(); + } + @Memoized public Optional typeRegistry() { if (fileTypes().isEmpty() && !fileDescriptorSetPath().isPresent()) { @@ -136,15 +151,8 @@ public Optional typeRegistry() { CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(fileTypes()) .messageTypeDescriptors()); } - if (fileDescriptorSetPath().isPresent()) { - try { - builder.add( - ProtoDescriptorUtils.getAllDescriptorsFromJvm(fileDescriptorSetPath().get()) - .messageTypeDescriptors()); - } catch (IOException e) { - throw new IllegalStateException( - "Failed to load descriptors from path: " + fileDescriptorSetPath().get(), e); - } + if (celDescriptors().isPresent()) { + builder.add(celDescriptors().get().messageTypeDescriptors()); } return Optional.of(builder.build()); } diff --git a/testing/src/main/java/dev/cel/testing/testrunner/CelTestSuiteTextProtoParser.java b/testing/src/main/java/dev/cel/testing/testrunner/CelTestSuiteTextProtoParser.java index 5e7e62498..9c0ab4720 100644 --- a/testing/src/main/java/dev/cel/testing/testrunner/CelTestSuiteTextProtoParser.java +++ b/testing/src/main/java/dev/cel/testing/testrunner/CelTestSuiteTextProtoParser.java @@ -22,6 +22,7 @@ import com.google.protobuf.TextFormat; import com.google.protobuf.TextFormat.ParseException; import com.google.protobuf.TypeRegistry; +import dev.cel.common.CelDescriptors; import dev.cel.common.annotations.Internal; import dev.cel.expr.conformance.test.InputValue; import dev.cel.expr.conformance.test.TestCase; @@ -30,6 +31,7 @@ import dev.cel.testing.testrunner.CelTestSuite.CelTestSection; import dev.cel.testing.testrunner.CelTestSuite.CelTestSection.CelTestCase; import dev.cel.testing.testrunner.CelTestSuite.CelTestSection.CelTestCase.Input.Binding; +import dev.cel.testing.utils.ProtoDescriptorUtils; import java.io.IOException; import java.util.Map; @@ -71,8 +73,10 @@ private TestSuite parseTestSuite( TypeRegistry typeRegistry = customTypeRegistry; ExtensionRegistry extensionRegistry = customExtensionRegistry; if (fileDescriptorSetPath != null) { - extensionRegistry = RegistryUtils.getExtensionRegistry(fileDescriptorSetPath); - typeRegistry = RegistryUtils.getTypeRegistry(fileDescriptorSetPath); + CelDescriptors descriptors = + ProtoDescriptorUtils.getDescriptorsFromFile(fileDescriptorSetPath); + extensionRegistry = RegistryUtils.getExtensionRegistry(descriptors); + typeRegistry = RegistryUtils.getTypeRegistry(descriptors); } TextFormat.Parser parser = TextFormat.Parser.newBuilder().setTypeRegistry(typeRegistry).build(); TestSuite.Builder builder = TestSuite.newBuilder(); diff --git a/testing/src/main/java/dev/cel/testing/testrunner/DefaultResultMatcher.java b/testing/src/main/java/dev/cel/testing/testrunner/DefaultResultMatcher.java index 2d33253af..279d591a2 100644 --- a/testing/src/main/java/dev/cel/testing/testrunner/DefaultResultMatcher.java +++ b/testing/src/main/java/dev/cel/testing/testrunner/DefaultResultMatcher.java @@ -22,11 +22,13 @@ import dev.cel.expr.MapValue; import dev.cel.bundle.Cel; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelDescriptors; import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime.Program; import dev.cel.testing.testrunner.CelTestSuite.CelTestSection.CelTestCase.Output; import dev.cel.testing.testrunner.ResultMatcher.ResultMatcherParams; import dev.cel.testing.testrunner.ResultMatcher.ResultMatcherParams.ComputedOutput; +import dev.cel.testing.utils.ProtoDescriptorUtils; import java.io.IOException; final class DefaultResultMatcher implements ResultMatcher { @@ -41,6 +43,10 @@ public void match(ResultMatcherParams params, Cel cel) throws Exception { "Error: " + params.computedOutput().error().getMessage(), params.computedOutput().error()); } + if (params.computedOutput().kind().equals(ComputedOutput.Kind.UNKNOWN_SET)) { + throw new AssertionError( + "Expected value but got UnknownSet: " + params.computedOutput().unknownSet()); + } CelAbstractSyntaxTree exprAst = cel.compile(result.resultExpr()).getAst(); Program exprProgram = cel.createProgram(exprAst); Object evaluationResult = null; @@ -59,6 +65,10 @@ public void match(ResultMatcherParams params, Cel cel) throws Exception { "Error: " + params.computedOutput().error().getMessage(), params.computedOutput().error()); } + if (params.computedOutput().kind().equals(ComputedOutput.Kind.UNKNOWN_SET)) { + throw new AssertionError( + "Expected value but got UnknownSet: " + params.computedOutput().unknownSet()); + } assertExprValue( params.computedOutput().exprValue(), toExprValue(result.resultValue(), params.resultType())); @@ -85,12 +95,14 @@ private static void assertExprValue(ExprValue exprValue, ExprValue expectedExprV throws IOException { String fileDescriptorSetPath = System.getProperty("file_descriptor_set_path"); if (fileDescriptorSetPath != null) { + CelDescriptors descriptors = + ProtoDescriptorUtils.getDescriptorsFromFile(fileDescriptorSetPath); assertThat(exprValue) .ignoringRepeatedFieldOrderOfFieldDescriptors( MapValue.getDescriptor().findFieldByName("entries")) .unpackingAnyUsing( - RegistryUtils.getTypeRegistry(fileDescriptorSetPath), - RegistryUtils.getExtensionRegistry(fileDescriptorSetPath)) + RegistryUtils.getTypeRegistry(descriptors), + RegistryUtils.getExtensionRegistry(descriptors)) .isEqualTo(expectedExprValue); } else { assertThat(exprValue) diff --git a/testing/src/main/java/dev/cel/testing/testrunner/RegistryUtils.java b/testing/src/main/java/dev/cel/testing/testrunner/RegistryUtils.java index b2f195606..a10904abb 100644 --- a/testing/src/main/java/dev/cel/testing/testrunner/RegistryUtils.java +++ b/testing/src/main/java/dev/cel/testing/testrunner/RegistryUtils.java @@ -13,44 +13,33 @@ // limitations under the License. package dev.cel.testing.testrunner; -import static dev.cel.testing.utils.ProtoDescriptorUtils.getAllDescriptorsFromJvm; + import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.DynamicMessage; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Message; import com.google.protobuf.TypeRegistry; -import dev.cel.common.internal.DefaultInstanceMessageFactory; -import java.io.IOException; -import java.util.NoSuchElementException; +import dev.cel.common.CelDescriptors; /** Utility class for creating registries from a file descriptor set. */ public final class RegistryUtils { /** Returns the {@link TypeRegistry} for the given file descriptor set. */ - public static TypeRegistry getTypeRegistry(String fileDescriptorSetPath) throws IOException { - return TypeRegistry.newBuilder() - .add(getAllDescriptorsFromJvm(fileDescriptorSetPath).messageTypeDescriptors()) - .build(); + public static TypeRegistry getTypeRegistry(CelDescriptors descriptors) { + return TypeRegistry.newBuilder().add(descriptors.messageTypeDescriptors()).build(); } /** Returns the {@link ExtensionRegistry} for the given file descriptor set. */ - public static ExtensionRegistry getExtensionRegistry(String fileDescriptorSetPath) - throws IOException { + public static ExtensionRegistry getExtensionRegistry(CelDescriptors descriptors) { ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); - getAllDescriptorsFromJvm(fileDescriptorSetPath) + descriptors .extensionDescriptors() .forEach( (descriptorName, descriptor) -> { if (descriptor.getType().equals(FieldDescriptor.Type.MESSAGE)) { - Message output = - DefaultInstanceMessageFactory.getInstance() - .getPrototype(descriptor.getMessageType()) - .orElseThrow( - () -> - new NoSuchElementException( - "Could not find a default message for: " - + descriptor.getFullName())); + Message output = DynamicMessage.getDefaultInstance(descriptor.getMessageType()); extensionRegistry.add(descriptor, output); } else { extensionRegistry.add(descriptor); diff --git a/testing/src/main/java/dev/cel/testing/testrunner/TestExecutor.java b/testing/src/main/java/dev/cel/testing/testrunner/TestExecutor.java index 6f6dff3c1..181d99c6f 100644 --- a/testing/src/main/java/dev/cel/testing/testrunner/TestExecutor.java +++ b/testing/src/main/java/dev/cel/testing/testrunner/TestExecutor.java @@ -236,6 +236,8 @@ public String describe() { testResult.setStatus(JUnitXmlReporter.TestResult.FAILURE); testResult.setThrowable(result.getFailures().get(0).getException()); testReporter.onTestFailure(testResult); + System.err.println("Test failed: " + testName); + result.getFailures().forEach(failure -> failure.getException().printStackTrace()); } } } diff --git a/testing/src/main/java/dev/cel/testing/testrunner/TestRunnerLibrary.java b/testing/src/main/java/dev/cel/testing/testrunner/TestRunnerLibrary.java index 2465d330e..69c365972 100644 --- a/testing/src/main/java/dev/cel/testing/testrunner/TestRunnerLibrary.java +++ b/testing/src/main/java/dev/cel/testing/testrunner/TestRunnerLibrary.java @@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableMap; import com.google.protobuf.Any; import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.DynamicMessage; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Message; import com.google.protobuf.TextFormat; @@ -38,10 +39,10 @@ import dev.cel.bundle.CelEnvironmentYamlParser; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelDescriptorUtil; +import dev.cel.common.CelDescriptors; import dev.cel.common.CelOptions; import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.CelValidationException; -import dev.cel.common.internal.DefaultInstanceMessageFactory; import dev.cel.policy.CelPolicy; import dev.cel.policy.CelPolicyCompilerFactory; import dev.cel.policy.CelPolicyParser; @@ -52,12 +53,10 @@ import dev.cel.testing.testrunner.CelTestSuite.CelTestSection.CelTestCase; import dev.cel.testing.testrunner.CelTestSuite.CelTestSection.CelTestCase.Input.Binding; import dev.cel.testing.testrunner.ResultMatcher.ResultMatcherParams; -import dev.cel.testing.utils.ProtoDescriptorUtils; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Optional; import java.util.logging.Logger; import org.jspecify.annotations.Nullable; @@ -201,16 +200,13 @@ private static Cel extendCel(CelTestContext celTestContext, CelOptions celOption // // Note: This needs to be added first because the config file may contain type information // regarding proto messages that need to be added to the cel object. - if (celTestContext.fileDescriptorSetPath().isPresent()) { + CelDescriptors descriptors = celTestContext.celDescriptors().orElse(null); + if (descriptors != null) { extendedCel = extendedCel .toCelBuilder() - .addMessageTypes( - ProtoDescriptorUtils.getAllDescriptorsFromJvm( - celTestContext.fileDescriptorSetPath().get()) - .messageTypeDescriptors()) - .setExtensionRegistry( - RegistryUtils.getExtensionRegistry(celTestContext.fileDescriptorSetPath().get())) + .addMessageTypes(descriptors.messageTypeDescriptors()) + .setExtensionRegistry(RegistryUtils.getExtensionRegistry(descriptors)) .build(); } @@ -369,22 +365,13 @@ private static Message unpackAny(Any any, CelTestContext celTestContext) throws "Proto descriptors are required for unpacking Any messages."); } Descriptor descriptor = - RegistryUtils.getTypeRegistry(celTestContext.fileDescriptorSetPath().get()) + RegistryUtils.getTypeRegistry(celTestContext.celDescriptors().get()) .getDescriptorForTypeUrl(any.getTypeUrl()); - return getDefaultInstance(descriptor) + return DynamicMessage.getDefaultInstance(descriptor) .getParserForType() .parseFrom( any.getValue(), - RegistryUtils.getExtensionRegistry(celTestContext.fileDescriptorSetPath().get())); - } - - private static Message getDefaultInstance(Descriptor descriptor) throws IOException { - return DefaultInstanceMessageFactory.getInstance() - .getPrototype(descriptor) - .orElseThrow( - () -> - new NoSuchElementException( - "Could not find a default message for: " + descriptor.getFullName())); + RegistryUtils.getExtensionRegistry(celTestContext.celDescriptors().get())); } private static Message getEvaluatedContextExpr( diff --git a/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel b/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel index 2947709e5..eea56752d 100644 --- a/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel @@ -15,19 +15,16 @@ java_library( tags = [ ], deps = [ - "//common:cel_descriptor_util", "//common:cel_descriptors", - "//common/internal:default_instance_message_factory", "//common/internal:proto_time_utils", "//common/types", "//common/types:type_providers", "//common/values", "//common/values:cel_byte_string", "//runtime:unknown_attributes", + "//testing:proto_descriptor_utils", "//testing/testrunner:registry_utils", "@cel_spec//proto/cel/expr:expr_java_proto", - "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", - "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven_android//:com_google_protobuf_protobuf_javalite", @@ -41,7 +38,6 @@ java_library( ], deps = [ "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_github_classgraph_classgraph", ], ) @@ -49,12 +45,9 @@ java_library( java_library( name = "proto_descriptor_utils", srcs = ["ProtoDescriptorUtils.java"], - tags = [ - ], deps = [ "//common:cel_descriptor_util", "//common:cel_descriptors", - "//testing/testrunner:class_loader_utils", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", ], diff --git a/testing/src/main/java/dev/cel/testing/utils/ClassLoaderUtils.java b/testing/src/main/java/dev/cel/testing/utils/ClassLoaderUtils.java index 652ec85c6..31f45d48f 100644 --- a/testing/src/main/java/dev/cel/testing/utils/ClassLoaderUtils.java +++ b/testing/src/main/java/dev/cel/testing/utils/ClassLoaderUtils.java @@ -15,51 +15,19 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableList; -import com.google.protobuf.Descriptors.Descriptor; import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ClassInfoList; import io.github.classgraph.ScanResult; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.util.logging.Logger; /** Utility class for loading classes using {@link ClassGraph}. */ public final class ClassLoaderUtils { - private static final Logger logger = Logger.getLogger(ClassLoaderUtils.class.getName()); - // Using `enableAllInfo()` to scan all class files upfront. This avoids repeated parsing // of class files by individual methods, improving efficiency. private static final Supplier CLASS_SCAN_RESULT = Suppliers.memoize(() -> new ClassGraph().enableAllInfo().scan()); - /** - * Loads all descriptor type classes from the JVM. - * - * @return A list of {@link Descriptor} objects representing the descriptors loaded from the JVM. - * @throws IOException If there is an error during the loading process. - */ - public static ImmutableList loadDescriptors() throws IOException { - ClassInfoList classInfoList = CLASS_SCAN_RESULT.get().getAllStandardClasses(); - ImmutableList.Builder compileTimeLoadedDescriptors = ImmutableList.builder(); - - for (ClassInfo classInfo : classInfoList) { - try { - Class classInfoClass = classInfo.loadClass(); - Descriptor descriptor = (Descriptor) classInfoClass.getMethod("getDescriptor").invoke(null); - compileTimeLoadedDescriptors.add(descriptor); - } catch (InvocationTargetException e) { - logger.severe( - "Failed to load descriptor: " + classInfo.getName() + " with error: " + e); - } catch (Exception e) { - // Ignore classes that do not have a getDescriptor method. - } - } - return compileTimeLoadedDescriptors.build(); - } - /** * Loads all subclasses of the given class from the JVM. * diff --git a/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java b/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java index 9bccecc95..10ab52786 100644 --- a/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java +++ b/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java @@ -24,11 +24,12 @@ import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.DynamicMessage; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Message; import com.google.protobuf.NullValue; import com.google.protobuf.TypeRegistry; -import dev.cel.common.internal.DefaultInstanceMessageFactory; +import dev.cel.common.CelDescriptors; import dev.cel.common.internal.ProtoTimeUtils; import dev.cel.common.types.CelType; import dev.cel.common.types.ListType; @@ -44,7 +45,6 @@ import java.time.Instant; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Optional; /** Utility class for ExprValue and Value type conversions during test execution. */ @@ -53,29 +53,23 @@ public final class ExprValueUtils { private ExprValueUtils() {} - /** * Converts a {@link Value} to a Java native object using the given file descriptor set to parse * `Any` messages. * * @param value The {@link Value} to convert. - * @param fileDescriptorSetPath The path to the file descriptor set. * @return The converted Java object. * @throws IOException If there's an error during conversion. */ - public static Object fromValue(Value value, String fileDescriptorSetPath) throws IOException { - TypeRegistry typeRegistry = RegistryUtils.getTypeRegistry(fileDescriptorSetPath); - ExtensionRegistry extensionRegistry = RegistryUtils.getExtensionRegistry(fileDescriptorSetPath); + public static Object fromValue(Value value, CelDescriptors descriptors) throws IOException { + TypeRegistry typeRegistry = RegistryUtils.getTypeRegistry(descriptors); + ExtensionRegistry extensionRegistry = RegistryUtils.getExtensionRegistry(descriptors); return fromValue(value, typeRegistry, extensionRegistry); } - /** - * Converts a {@link Value} to a Java native object. - * - * @param value The {@link Value} to convert. - * @return The converted Java object. - * @throws IOException If there's an error during conversion. - */ + public static Object fromValue(Value value, String fileDescriptorSetPath) throws IOException { + return fromValue(value, ProtoDescriptorUtils.getDescriptorsFromFile(fileDescriptorSetPath)); + } /** * Converts a {@link Value} to a Java native object using custom registries. @@ -97,7 +91,7 @@ public static Object fromValue( "Unknown type, descriptor was not found in registry: " + value.getObjectValue().getTypeUrl()); } - Message prototype = getDefaultInstance(descriptor); + Message prototype = DynamicMessage.getDefaultInstance(descriptor); return prototype .getParserForType() .parseFrom(value.getObjectValue().getValue(), extensionRegistry); @@ -197,7 +191,8 @@ public static Value toValue(Object object, CelType type) throws Exception { if (object instanceof dev.cel.expr.Value) { object = Value.parseFrom( - ((dev.cel.expr.Value) object).toByteArray(), ExtensionRegistry.getEmptyRegistry()); + ((dev.cel.expr.Value) object).toByteArray(), + ExtensionRegistry.getEmptyRegistry()); } if (object instanceof Value) { return (Value) object; @@ -302,16 +297,4 @@ public static Value toValue(Object object, CelType type) throws Exception { throw new IllegalArgumentException( String.format("Unexpected result type: %s", object.getClass())); } - - private static Message getDefaultInstance(Descriptor descriptor) { - return DefaultInstanceMessageFactory.getInstance() - .getPrototype(descriptor) - .orElseThrow( - () -> - new NoSuchElementException( - "Could not find a default message for: " + descriptor.getFullName())); - } - - - } diff --git a/testing/src/main/java/dev/cel/testing/utils/ProtoDescriptorUtils.java b/testing/src/main/java/dev/cel/testing/utils/ProtoDescriptorUtils.java index b6fa2e64b..880c03e12 100644 --- a/testing/src/main/java/dev/cel/testing/utils/ProtoDescriptorUtils.java +++ b/testing/src/main/java/dev/cel/testing/utils/ProtoDescriptorUtils.java @@ -1,4 +1,4 @@ -// Copyright 2025 Google LLC +// Copyright 2026 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,18 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package dev.cel.testing.utils; -import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.common.collect.ImmutableSet.toImmutableSet; -import static dev.cel.testing.utils.ClassLoaderUtils.loadDescriptors; +package dev.cel.testing.utils; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import com.google.common.io.Files; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; -import com.google.protobuf.Descriptors.Descriptor; -import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.ExtensionRegistry; import dev.cel.common.CelDescriptorUtil; import dev.cel.common.CelDescriptors; @@ -33,30 +26,15 @@ public final class ProtoDescriptorUtils { /** - * Returns all the descriptors from the JVM. + * Returns all the descriptors from the file descriptor set file. * * @return The {@link CelDescriptors} object containing all the descriptors. */ - public static CelDescriptors getAllDescriptorsFromJvm(String fileDescriptorSetPath) + public static CelDescriptors getDescriptorsFromFile(String fileDescriptorSetPath) throws IOException { - ImmutableList compileTimeLoadedDescriptors = loadDescriptors(); FileDescriptorSet fileDescriptorSet = getFileDescriptorSet(fileDescriptorSetPath); - ImmutableSet runtimeFileDescriptorNames = - CelDescriptorUtil.getFileDescriptorsFromFileDescriptorSet(fileDescriptorSet).stream() - .map(FileDescriptor::getFullName) - .collect(toImmutableSet()); - - // Get all the file descriptors from the descriptors which are loaded from the JVM and use the - // ones which match the ones provided by the user in the file descriptor set. - ImmutableList userProvidedFileDescriptors = - CelDescriptorUtil.getFileDescriptorsForDescriptors(compileTimeLoadedDescriptors).stream() - .filter( - fileDescriptor -> runtimeFileDescriptorNames.contains(fileDescriptor.getFullName())) - .collect(toImmutableList()); - - // Get all the descriptors from the file descriptors above which include nested, extension and - // message type descriptors as well. - return CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(userProvidedFileDescriptors); + return CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( + CelDescriptorUtil.getFileDescriptorsFromFileDescriptorSet(fileDescriptorSet)); } private static FileDescriptorSet getFileDescriptorSet(String fileDescriptorSetPath) diff --git a/testing/src/test/java/dev/cel/testing/testrunner/BUILD.bazel b/testing/src/test/java/dev/cel/testing/testrunner/BUILD.bazel index 755ef732d..a12654d2c 100644 --- a/testing/src/test/java/dev/cel/testing/testrunner/BUILD.bazel +++ b/testing/src/test/java/dev/cel/testing/testrunner/BUILD.bazel @@ -51,6 +51,7 @@ java_library( name = "custom_variable_binding_user_test", srcs = ["CustomVariableBindingUserTest.java"], deps = [ + "//bundle:cel", "//testing/testrunner:cel_test_context", "//testing/testrunner:cel_user_test_template", "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", @@ -186,10 +187,6 @@ cel_java_test( name = "custom_variable_binding_test_runner_sample", cel_expr = "custom_variable_bindings/policy.yaml", config = "custom_variable_bindings/config.yaml", - proto_deps = [ - "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_proto", - "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_proto", - ], test_data_path = "//testing/src/test/resources/policy", test_src = ":custom_variable_binding_user_test", test_suite = "custom_variable_bindings/tests.yaml", diff --git a/testing/src/test/java/dev/cel/testing/testrunner/CustomVariableBindingUserTest.java b/testing/src/test/java/dev/cel/testing/testrunner/CustomVariableBindingUserTest.java index 707b5eef9..37382052c 100644 --- a/testing/src/test/java/dev/cel/testing/testrunner/CustomVariableBindingUserTest.java +++ b/testing/src/test/java/dev/cel/testing/testrunner/CustomVariableBindingUserTest.java @@ -15,7 +15,8 @@ package dev.cel.testing.testrunner; import com.google.common.collect.ImmutableMap; -import com.google.protobuf.Any; +import com.google.protobuf.ExtensionRegistry; +import dev.cel.bundle.CelFactory; import dev.cel.expr.conformance.proto2.TestAllTypes; import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; import org.junit.runner.RunWith; @@ -29,15 +30,24 @@ public class CustomVariableBindingUserTest extends CelUserTestTemplate { public CustomVariableBindingUserTest() { - super( - CelTestContext.newBuilder() - .setVariableBindings( - ImmutableMap.of( - "spec", - Any.pack( - TestAllTypes.newBuilder() - .setExtension(TestAllTypesExtensions.int32Ext, 1) - .build()))) - .build()); + super(newTestContext()); + } + + private static CelTestContext newTestContext() { + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(TestAllTypesExtensions.int32Ext); + + return CelTestContext.newBuilder() + .setCel( + CelFactory.standardCelBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .addFileTypes(TestAllTypesExtensions.getDescriptor()) + .setExtensionRegistry(registry) + .build()) + .setVariableBindings( + ImmutableMap.of( + "spec", + TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 1).build())) + .build(); } }