diff --git a/eval/eval/BUILD b/eval/eval/BUILD index 37b88db94..13efe4c0e 100644 --- a/eval/eval/BUILD +++ b/eval/eval/BUILD @@ -550,6 +550,7 @@ cc_test( deps = [ ":cel_expression_flat_impl", ":evaluator_core", + "//base:attributes", "//base:data", "//common:constant", "//common:expr", @@ -587,14 +588,10 @@ cc_test( deps = [ ":cel_expression_flat_impl", ":evaluator_core", - "//base:attributes", "//base:data", "//common:expr", "//eval/public:activation", - "//eval/public:cel_attribute", "//eval/public:cel_value", - "//eval/public:unknown_attribute_set", - "//eval/public:unknown_set", "//internal:status_macros", "//internal:testing", "//runtime:runtime_options", @@ -856,14 +853,9 @@ cc_test( ":cel_expression_flat_impl", ":evaluator_core", ":ternary_step", - "//base:attributes", "//base:data", - "//common:expr", "//eval/public:activation", - "//eval/public:cel_attribute", "//eval/public:cel_value", - "//eval/public:unknown_attribute_set", - "//eval/public:unknown_set", "//internal:testing", "//runtime:runtime_options", "//runtime/internal:runtime_env", diff --git a/eval/eval/create_map_step_test.cc b/eval/eval/create_map_step_test.cc index 163fed860..f9f11516c 100644 --- a/eval/eval/create_map_step_test.cc +++ b/eval/eval/create_map_step_test.cc @@ -136,25 +136,6 @@ TEST_P(CreateMapStepTest, TestCreateEmptyMap) { ASSERT_EQ(cel_map->size(), 0); } -// Test message creation if unknown argument is passed -TEST(CreateMapStepTest, TestMapCreateWithUnknown) { - absl_nonnull std::shared_ptr env = NewTestingRuntimeEnv(); - Arena arena; - UnknownSet unknown_set; - std::vector> entries; - - std::vector kKeys = {"test2", "test1"}; - - entries.push_back( - {CelValue::CreateString(&kKeys[0]), CelValue::CreateInt64(2)}); - entries.push_back({CelValue::CreateString(&kKeys[1]), - CelValue::CreateUnknownSet(&unknown_set)}); - - ASSERT_OK_AND_ASSIGN(CelValue result, RunCreateMapExpression( - env, entries, &arena, true, false)); - ASSERT_TRUE(result.IsUnknownSet()); -} - TEST(CreateMapStepTest, TestMapCreateWithError) { absl_nonnull std::shared_ptr env = NewTestingRuntimeEnv(); Arena arena; @@ -172,41 +153,6 @@ TEST(CreateMapStepTest, TestMapCreateWithError) { EXPECT_THAT(*result.ErrorOrDie(), StatusIs(absl::StatusCode::kCancelled)); } -TEST(CreateMapStepTest, TestMapCreateWithErrorRecursiveProgram) { - absl_nonnull std::shared_ptr env = NewTestingRuntimeEnv(); - Arena arena; - UnknownSet unknown_set; - absl::Status error = absl::CancelledError(); - std::vector> entries; - entries.push_back({CelValue::CreateStringView("foo"), - CelValue::CreateUnknownSet(&unknown_set)}); - entries.push_back( - {CelValue::CreateStringView("bar"), CelValue::CreateError(&error)}); - - ASSERT_OK_AND_ASSIGN(CelValue result, RunCreateMapExpression( - env, entries, &arena, true, true)); - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(*result.ErrorOrDie(), StatusIs(absl::StatusCode::kCancelled)); -} - -TEST(CreateMapStepTest, TestMapCreateWithUnknownRecursiveProgram) { - absl_nonnull std::shared_ptr env = NewTestingRuntimeEnv(); - Arena arena; - UnknownSet unknown_set; - std::vector> entries; - - std::vector kKeys = {"test2", "test1"}; - - entries.push_back( - {CelValue::CreateString(&kKeys[0]), CelValue::CreateInt64(2)}); - entries.push_back({CelValue::CreateString(&kKeys[1]), - CelValue::CreateUnknownSet(&unknown_set)}); - - ASSERT_OK_AND_ASSIGN(CelValue result, RunCreateMapExpression( - env, entries, &arena, true, true)); - ASSERT_TRUE(result.IsUnknownSet()); -} - // Test that String Map is created successfully. TEST_P(CreateMapStepTest, TestCreateStringMap) { Arena arena; diff --git a/eval/eval/create_struct_step_test.cc b/eval/eval/create_struct_step_test.cc index e348ecd20..c6fa6f036 100644 --- a/eval/eval/create_struct_step_test.cc +++ b/eval/eval/create_struct_step_test.cc @@ -229,34 +229,6 @@ TEST(CreateCreateStructStepTest, TestMessageCreateErrorRecursive) { StatusIs(absl::StatusCode::kCancelled)); } -// Test message creation if unknown argument is passed -TEST(CreateCreateStructStepTest, TestMessageCreateWithUnknown) { - absl_nonnull std::shared_ptr env = NewTestingRuntimeEnv(); - Arena arena; - TestMessage test_msg; - UnknownSet unknown_set; - - auto eval_status = - RunExpression(env, "bool_value", CelValue::CreateUnknownSet(&unknown_set), - &arena, true, /*enable_recursive_planning=*/false); - ASSERT_THAT(eval_status, IsOk()); - ASSERT_TRUE(eval_status->IsUnknownSet()); -} - -// Test message creation if unknown argument is passed -TEST(CreateCreateStructStepTest, TestMessageCreateWithUnknownRecursive) { - absl_nonnull std::shared_ptr env = NewTestingRuntimeEnv(); - Arena arena; - TestMessage test_msg; - UnknownSet unknown_set; - - auto eval_status = - RunExpression(env, "bool_value", CelValue::CreateUnknownSet(&unknown_set), - &arena, true, /*enable_recursive_planning=*/true); - ASSERT_THAT(eval_status, IsOk()); - ASSERT_TRUE(eval_status->IsUnknownSet()) << eval_status->DebugString(); -} - // Test that fields of type bool are set correctly TEST_P(CreateCreateStructStepTest, TestSetBoolField) { TestMessage test_msg; diff --git a/eval/eval/function_step_test.cc b/eval/eval/function_step_test.cc index 9cb338af2..9b9ce6a36 100644 --- a/eval/eval/function_step_test.cc +++ b/eval/eval/function_step_test.cc @@ -12,6 +12,8 @@ #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" +#include "base/attribute.h" +#include "base/attribute_set.h" #include "base/type_provider.h" #include "common/constant.h" #include "common/expr.h" @@ -162,7 +164,8 @@ class SinkFunction : public CelFunction { // Create and initialize a registry with some default functions. void AddDefaults(CelFunctionRegistry& registry) { - static UnknownSet* unknown_set = new UnknownSet(); + static UnknownSet* unknown_set = + new UnknownSet(cel::AttributeSet({cel::Attribute("foo")})); EXPECT_TRUE(registry .Register(std::make_unique( CelValue::CreateInt64(3), "Const3")) @@ -863,7 +866,7 @@ TEST(FunctionStepTestUnknownFunctionResults, UnknownVsErrorPrecedenceTest) { CelError error0 = absl::CancelledError(); CelValue error_value = CelValue::CreateError(&error0); - UnknownSet unknown_set; + UnknownSet unknown_set(cel::AttributeSet({cel::Attribute("foo")})); CelValue unknown_value = CelValue::CreateUnknownSet(&unknown_set); ASSERT_OK(registry.Register( @@ -960,7 +963,7 @@ class NullFunction : public CelFunction { TEST(FunctionStepStrictnessTest, IfFunctionStrictAndGivenUnknownSkipsInvocation) { - UnknownSet unknown_set; + UnknownSet unknown_set(cel::AttributeSet({cel::Attribute("foo")})); CelFunctionRegistry registry; ASSERT_THAT(registry.Register(std::make_unique( CelValue::CreateUnknownSet(&unknown_set), "ConstUnknown")), @@ -991,7 +994,7 @@ TEST(FunctionStepStrictnessTest, } TEST(FunctionStepStrictnessTest, IfFunctionNonStrictAndGivenUnknownInvokesIt) { - UnknownSet unknown_set; + UnknownSet unknown_set(cel::AttributeSet({cel::Attribute("foo")})); CelFunctionRegistry registry; ASSERT_THAT(registry.Register(std::make_unique( CelValue::CreateUnknownSet(&unknown_set), "ConstUnknown")), diff --git a/eval/eval/logic_step_test.cc b/eval/eval/logic_step_test.cc index e82c4b7cf..59888b20a 100644 --- a/eval/eval/logic_step_test.cc +++ b/eval/eval/logic_step_test.cc @@ -3,23 +3,17 @@ #include #include #include -#include #include "absl/base/nullability.h" #include "absl/status/status.h" #include "absl/status/status_matchers.h" #include "absl/strings/string_view.h" -#include "base/attribute.h" -#include "base/attribute_set.h" #include "base/type_provider.h" #include "common/expr.h" #include "eval/eval/cel_expression_flat_impl.h" #include "eval/eval/evaluator_core.h" #include "eval/public/activation.h" -#include "eval/public/cel_attribute.h" #include "eval/public/cel_value.h" -#include "eval/public/unknown_attribute_set.h" -#include "eval/public/unknown_set.h" #include "internal/status_macros.h" #include "internal/testing.h" #include "runtime/internal/runtime_env.h" @@ -32,14 +26,11 @@ namespace google::api::expr::runtime { namespace { using ::absl_testing::IsOk; -using ::cel::Attribute; -using ::cel::AttributeSet; using ::cel::Expr; using ::cel::TypeProvider; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::runtime_internal::RuntimeEnv; using ::google::protobuf::Arena; -using ::testing::Eq; class LogicStepTest : public testing::TestWithParam { public: @@ -193,113 +184,6 @@ TEST_P(LogicStepTest, TestOrLogicErrorHandling) { ASSERT_TRUE(result.BoolOrDie()); } -TEST_F(LogicStepTest, TestAndLogicUnknownHandling) { - CelValue result; - UnknownSet unknown_set; - CelError cel_error = absl::CancelledError(); - CelValue unknown_value = CelValue::CreateUnknownSet(&unknown_set); - CelValue error_value = CelValue::CreateError(&cel_error); - absl::Status status = EvaluateLogic(unknown_value, CelValue::CreateBool(true), - false, &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - status = EvaluateLogic(CelValue::CreateBool(true), unknown_value, false, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - status = EvaluateLogic(CelValue::CreateBool(false), unknown_value, false, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsBool()); - ASSERT_FALSE(result.BoolOrDie()); - - status = EvaluateLogic(unknown_value, CelValue::CreateBool(false), false, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsBool()); - ASSERT_FALSE(result.BoolOrDie()); - - status = EvaluateLogic(error_value, unknown_value, false, &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - status = EvaluateLogic(unknown_value, error_value, false, &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - CelAttribute attr0("name0", {}), attr1("name1", {}); - UnknownAttributeSet unknown_attr_set0({attr0}); - UnknownAttributeSet unknown_attr_set1({attr1}); - UnknownSet unknown_set0(unknown_attr_set0); - UnknownSet unknown_set1(unknown_attr_set1); - - EXPECT_THAT(unknown_attr_set0.size(), Eq(1)); - EXPECT_THAT(unknown_attr_set1.size(), Eq(1)); - - status = EvaluateLogic(CelValue::CreateUnknownSet(&unknown_set0), - CelValue::CreateUnknownSet(&unknown_set1), false, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - ASSERT_THAT(result.UnknownSetOrDie()->unknown_attributes().size(), Eq(2)); -} - -TEST_F(LogicStepTest, TestOrLogicUnknownHandling) { - CelValue result; - UnknownSet unknown_set; - CelError cel_error = absl::CancelledError(); - CelValue unknown_value = CelValue::CreateUnknownSet(&unknown_set); - CelValue error_value = CelValue::CreateError(&cel_error); - absl::Status status = EvaluateLogic( - unknown_value, CelValue::CreateBool(false), true, &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - status = EvaluateLogic(CelValue::CreateBool(false), unknown_value, true, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - status = EvaluateLogic(CelValue::CreateBool(true), unknown_value, true, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsBool()); - ASSERT_TRUE(result.BoolOrDie()); - - status = EvaluateLogic(unknown_value, CelValue::CreateBool(true), true, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsBool()); - ASSERT_TRUE(result.BoolOrDie()); - - status = EvaluateLogic(unknown_value, error_value, true, &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - status = EvaluateLogic(error_value, unknown_value, true, &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - CelAttribute attr0("name0", {}), attr1("name1", {}); - UnknownAttributeSet unknown_attr_set0({attr0}); - UnknownAttributeSet unknown_attr_set1({attr1}); - - UnknownSet unknown_set0(unknown_attr_set0); - UnknownSet unknown_set1(unknown_attr_set1); - - EXPECT_THAT(unknown_attr_set0.size(), Eq(1)); - EXPECT_THAT(unknown_attr_set1.size(), Eq(1)); - - status = EvaluateLogic(CelValue::CreateUnknownSet(&unknown_set0), - CelValue::CreateUnknownSet(&unknown_set1), true, - &result, true); - ASSERT_THAT(status, IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - ASSERT_THAT(result.UnknownSetOrDie()->unknown_attributes().size(), Eq(2)); -} - INSTANTIATE_TEST_SUITE_P(LogicStepTest, LogicStepTest, testing::Bool()); } // namespace diff --git a/eval/eval/select_step_test.cc b/eval/eval/select_step_test.cc index 68c6f6f50..4963550b4 100644 --- a/eval/eval/select_step_test.cc +++ b/eval/eval/select_step_test.cc @@ -290,26 +290,6 @@ TEST_F(SelectStepTest, MapPresenseIsErrorTest) { EXPECT_EQ(result.ErrorOrDie()->code(), absl::StatusCode::kInvalidArgument); } -TEST_F(SelectStepTest, MapPresenseIsTrueWithUnknownTest) { - UnknownSet unknown_set; - std::string key1 = "key1"; - std::vector> key_values{ - {CelValue::CreateString(&key1), - CelValue::CreateUnknownSet(&unknown_set)}}; - - auto map_value = CreateContainerBackedMap( - absl::Span>(key_values)) - .value(); - - RunExpressionOptions options; - options.enable_unknowns = true; - - ASSERT_OK_AND_ASSIGN(CelValue result, - RunExpression(map_value.get(), "key1", true, options)); - ASSERT_TRUE(result.IsBool()); - EXPECT_EQ(result.BoolOrDie(), true); -} - TEST_P(SelectStepConformanceTest, FieldIsNotPresentInProtoTest) { TestMessage message; diff --git a/eval/eval/ternary_step_test.cc b/eval/eval/ternary_step_test.cc index 5d5ac6ae4..d1011f247 100644 --- a/eval/eval/ternary_step_test.cc +++ b/eval/eval/ternary_step_test.cc @@ -3,20 +3,14 @@ #include #include #include -#include #include "absl/base/nullability.h" #include "absl/status/status.h" -#include "base/attribute_set.h" #include "base/type_provider.h" -#include "common/expr.h" #include "eval/eval/cel_expression_flat_impl.h" #include "eval/eval/evaluator_core.h" #include "eval/public/activation.h" -#include "eval/public/cel_attribute.h" #include "eval/public/cel_value.h" -#include "eval/public/unknown_attribute_set.h" -#include "eval/public/unknown_set.h" #include "internal/testing.h" #include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" @@ -28,13 +22,11 @@ namespace google::api::expr::runtime { namespace { using ::absl_testing::IsOk; -using ::cel::Expr; using ::cel::RuntimeOptions; using ::cel::TypeProvider; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::runtime_internal::RuntimeEnv; using ::google::protobuf::Arena; -using ::testing::Eq; class LogicStepTest : public testing::TestWithParam { public: @@ -115,66 +107,6 @@ TEST_P(LogicStepTest, TestErrorHandling) { ASSERT_FALSE(result.BoolOrDie()); } -TEST_F(LogicStepTest, TestUnknownHandling) { - CelValue result; - UnknownSet unknown_set; - CelError cel_error = absl::CancelledError(); - CelValue unknown_value = CelValue::CreateUnknownSet(&unknown_set); - CelValue error_value = CelValue::CreateError(&cel_error); - ASSERT_THAT(EvaluateLogic(unknown_value, CelValue::CreateBool(true), - CelValue::CreateBool(false), &result, true), - IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - ASSERT_THAT(EvaluateLogic(CelValue::CreateBool(true), unknown_value, - CelValue::CreateBool(false), &result, true), - IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - ASSERT_THAT(EvaluateLogic(CelValue::CreateBool(false), unknown_value, - CelValue::CreateBool(false), &result, true), - IsOk()); - ASSERT_TRUE(result.IsBool()); - ASSERT_FALSE(result.BoolOrDie()); - - ASSERT_THAT(EvaluateLogic(error_value, unknown_value, - CelValue::CreateBool(false), &result, true), - IsOk()); - ASSERT_TRUE(result.IsError()); - - ASSERT_THAT(EvaluateLogic(unknown_value, error_value, - CelValue::CreateBool(false), &result, true), - IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - - Expr expr0; - auto& ident_expr0 = expr0.mutable_ident_expr(); - ident_expr0.set_name("name0"); - - Expr expr1; - auto& ident_expr1 = expr1.mutable_ident_expr(); - ident_expr1.set_name("name1"); - - CelAttribute attr0(expr0.ident_expr().name(), {}), - attr1(expr1.ident_expr().name(), {}); - UnknownAttributeSet unknown_attr_set0({attr0}); - UnknownAttributeSet unknown_attr_set1({attr1}); - UnknownSet unknown_set0(unknown_attr_set0); - UnknownSet unknown_set1(unknown_attr_set1); - - EXPECT_THAT(unknown_attr_set0.size(), Eq(1)); - EXPECT_THAT(unknown_attr_set1.size(), Eq(1)); - - ASSERT_THAT(EvaluateLogic(CelValue::CreateUnknownSet(&unknown_set0), - CelValue::CreateUnknownSet(&unknown_set1), - CelValue::CreateBool(false), &result, true), - IsOk()); - ASSERT_TRUE(result.IsUnknownSet()); - const auto& attrs = result.UnknownSetOrDie()->unknown_attributes(); - ASSERT_THAT(attrs, testing::SizeIs(1)); - EXPECT_THAT(attrs.begin()->variable_name(), Eq("name0")); -} - INSTANTIATE_TEST_SUITE_P(LogicStepTest, LogicStepTest, testing::Bool()); } // namespace diff --git a/eval/tests/BUILD b/eval/tests/BUILD index 78a08ed0c..a9f081db0 100644 --- a/eval/tests/BUILD +++ b/eval/tests/BUILD @@ -110,6 +110,39 @@ cc_test( ], ) +cc_test( + name = "modern_unknown_test", + srcs = [ + "modern_unknown_test.cc", + ], + deps = [ + "//base:attributes", + "//common:value", + "//extensions:bindings_ext", + "//extensions:comprehensions_v2_macros", + "//internal:testing", + "//internal:testing_descriptor_pool", + "//internal:testing_message_factory", + "//parser", + "//parser:options", + "//parser:parser_interface", + "//runtime", + "//runtime:activation", + "//runtime:constant_folding", + "//runtime:optional_types", + "//runtime:reference_resolver", + "//runtime:runtime_options", + "//runtime:standard_runtime_builder_factory", + "@com_google_absl//absl/log:absl_check", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:status_matchers", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings:string_view", + "@com_google_protobuf//:protobuf", + "@com_google_protobuf//:struct_cc_proto", + ], +) + cc_test( name = "allocation_benchmark_test", size = "small", diff --git a/eval/tests/modern_unknown_test.cc b/eval/tests/modern_unknown_test.cc new file mode 100644 index 000000000..6575e45f3 --- /dev/null +++ b/eval/tests/modern_unknown_test.cc @@ -0,0 +1,503 @@ +// 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. +// 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. + +#include +#include + +#include "google/protobuf/struct.pb.h" +#include "absl/log/absl_check.h" +#include "absl/status/status.h" +#include "absl/status/status_matchers.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "base/attribute.h" +#include "common/value.h" +#include "extensions/bindings_ext.h" +#include "extensions/comprehensions_v2_macros.h" +#include "internal/testing.h" +#include "internal/testing_descriptor_pool.h" +#include "internal/testing_message_factory.h" +#include "parser/options.h" +#include "parser/parser.h" +#include "parser/parser_interface.h" +#include "runtime/activation.h" +#include "runtime/constant_folding.h" +#include "runtime/optional_types.h" +#include "runtime/reference_resolver.h" +#include "runtime/runtime.h" +#include "runtime/runtime_options.h" +#include "runtime/standard_runtime_builder_factory.h" +#include "google/protobuf/arena.h" +#include "google/protobuf/json/json.h" +#include "google/protobuf/text_format.h" + +namespace { + +using absl_testing::IsOk; +using ::testing::UnorderedElementsAre; + +class ModernUnknownTest : public ::testing::Test { + public: + void SetUp() override { + auto parser_builder = cel::NewParserBuilder(cel::ParserOptions{ + .enable_optional_syntax = true, + }); + ABSL_CHECK_OK(cel::extensions::RegisterComprehensionsV2Macros( // Crash OK + *parser_builder)); + for (const auto& macro : cel::extensions::bindings_macros()) { + ABSL_CHECK_OK(parser_builder->AddMacro(macro)); // Crash OK + } + auto status_or_parser = parser_builder->Build(); + ABSL_CHECK_OK(status_or_parser); // Crash OK + parser_ = *std::move(status_or_parser); + auto status_or_runtime_builder = cel::CreateStandardRuntimeBuilder( + cel::internal::GetTestingDescriptorPool(), + cel::RuntimeOptions{ + .unknown_processing = + cel::UnknownProcessingOptions::kAttributeAndFunction, + .enable_missing_attribute_errors = true, + .enable_qualified_type_identifiers = true}); + ABSL_CHECK_OK(status_or_runtime_builder); // Crash OK + auto runtime_builder = *std::move(status_or_runtime_builder); + ABSL_CHECK_OK(cel::EnableReferenceResolver( + runtime_builder, + cel::ReferenceResolverEnabled::kCheckedExpressionOnly)); + ABSL_CHECK_OK(cel::extensions::EnableConstantFolding( + runtime_builder, cel::internal::GetTestingMessageFactory())); + ABSL_CHECK_OK(cel::extensions::EnableOptionalTypes(runtime_builder)); + auto status_or_runtime = std::move(runtime_builder).Build(); + ABSL_CHECK_OK(status_or_runtime); // Crash OK + runtime_ = *std::move(status_or_runtime); + } + + std::unique_ptr CreateProgram(absl::string_view text) { + auto status_or_source = parser_->PrepareSource(text); + ABSL_CHECK_OK(status_or_source); // Crash OK + auto source = *std::move(status_or_source); + auto status_or_ast = parser_->Parse(*source); + ABSL_CHECK_OK(status_or_ast); // Crash OK + auto ast = *std::move(status_or_ast); + auto status_or_program = runtime_->CreateProgram(std::move(ast)); + ABSL_CHECK_OK(status_or_program); // Crash OK + return *std::move(status_or_program); + } + + void TearDown() override { + parser_.reset(); + runtime_.reset(); + } + + template + void BindProtoToActivation(absl::string_view variable, + absl::string_view text) { + T message; + ABSL_CHECK( + google::protobuf::TextFormat::ParseFromString(text, &message)); // Crash OK + activation_.InsertOrAssignValue( + variable, + cel::Value::FromMessage( + std::move(message), cel::internal::GetTestingDescriptorPool(), + cel::internal::GetTestingMessageFactory(), &arena_)); + } + + void BindJsonToActivation(absl::string_view variable, + absl::string_view text) { + google::protobuf::Value message; + ABSL_CHECK_OK( + google::protobuf::json::JsonStringToMessage(text, &message)); // Crash OK + activation_.InsertOrAssignValue( + variable, + cel::Value::FromMessage( + std::move(message), cel::internal::GetTestingDescriptorPool(), + cel::internal::GetTestingMessageFactory(), &arena_)); + } + + absl::StatusOr Evaluate(const cel::Program& program) { + return program.Evaluate(&arena_, cel::internal::GetTestingMessageFactory(), + activation_); + } + + protected: + std::unique_ptr parser_; + std::unique_ptr runtime_; + google::protobuf::Arena arena_; + cel::Activation activation_; +}; + +TEST_F(ModernUnknownTest, And) { + auto program = CreateProgram(R"cel(var1 && var2)cel"); + + { + // unk && true + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue("var2", cel::TrueValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } + { + // true && unk + activation_.InsertOrAssignValue("var1", cel::TrueValue()); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var2"))); + } + { + // false && unk + activation_.InsertOrAssignValue("var1", cel::FalseValue()); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsFalse()); + } + { + // unk && false + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue("var2", cel::FalseValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsFalse()); + } + { + // error && unk + activation_.InsertOrAssignValue( + "var1", cel::ErrorValue::From(absl::CancelledError(), &arena_)); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var2"))); + } + { + // unk && error + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue( + "var2", cel::ErrorValue::From(absl::CancelledError(), &arena_)); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } + { + // unk && unk + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1"), + cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT( + result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"), cel::Attribute("var2"))); + } +} + +TEST_F(ModernUnknownTest, Or) { + auto program = CreateProgram(R"cel(var1 || var2)cel"); + + { + // unk || true + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue("var2", cel::TrueValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsTrue()); + } + { + // true || unk + activation_.InsertOrAssignValue("var1", cel::TrueValue()); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsTrue()); + } + { + // false || unk + activation_.InsertOrAssignValue("var1", cel::FalseValue()); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var2"))); + } + { + // unk || false + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue("var2", cel::FalseValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } + { + // error || unk + activation_.InsertOrAssignValue( + "var1", cel::ErrorValue::From(absl::CancelledError(), &arena_)); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var2"))); + } + { + // unk || error + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue( + "var2", cel::ErrorValue::From(absl::CancelledError(), &arena_)); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } + { + // unk || unk + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1"), + cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT( + result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"), cel::Attribute("var2"))); + } +} + +TEST_F(ModernUnknownTest, Ternary) { + auto program = CreateProgram(R"cel(var1 ? var2 : var3)cel"); + + { + // unk ? true : false + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue("var2", cel::TrueValue()); + activation_.InsertOrAssignValue("var3", cel::FalseValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } + { + // true ? unk : false + activation_.InsertOrAssignValue("var1", cel::TrueValue()); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + activation_.InsertOrAssignValue("var3", cel::FalseValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var2"))); + } + { + // false ? unk : false + activation_.InsertOrAssignValue("var1", cel::FalseValue()); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + activation_.InsertOrAssignValue("var3", cel::FalseValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsFalse()); + } + { + // error ? unk : false + activation_.InsertOrAssignValue( + "var1", cel::ErrorValue::From(absl::CancelledError(), &arena_)); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var2")}), + IsOk()); + activation_.InsertOrAssignValue("var3", cel::FalseValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsError()); + } + { + // unk ? error : false + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + activation_.InsertOrAssignValue( + "var2", cel::ErrorValue::From(absl::CancelledError(), &arena_)); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + activation_.InsertOrAssignValue("var3", cel::FalseValue()); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } + { + // unk ? unk : false + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1"), + cel::AttributePattern("var2")}), + IsOk()); + activation_.InsertOrAssignValue("var3", cel::FalseValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } + { + // unk ? true : unk + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1"), + cel::AttributePattern("var3")}), + IsOk()); + activation_.InsertOrAssignValue("var2", cel::TrueValue()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); + } +} + +TEST_F(ModernUnknownTest, ListUnknown) { + auto program = CreateProgram(R"cel([var1, var2])cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1"), + cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT( + result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"), cel::Attribute("var2"))); +} + +TEST_F(ModernUnknownTest, ListErrorUnknown) { + auto program = CreateProgram(R"cel([var1, 1 / 0])cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + EXPECT_TRUE(result.IsError()); +} + +TEST_F(ModernUnknownTest, MapUnknown) { + auto program = CreateProgram(R"cel({"foo": var1, "bar": var2})cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1"), + cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT( + result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"), cel::Attribute("var2"))); +} + +TEST_F(ModernUnknownTest, MapErrorUnknown) { + auto program = CreateProgram(R"cel({"foo": var1, "bar": 1 / 0})cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + EXPECT_TRUE(result.IsError()); +} + +TEST_F(ModernUnknownTest, StructUnknown) { + auto program = CreateProgram( + R"cel(cel.expr.conformance.proto3.TestAllTypes{single_int64: var1, single_uint64: var2})cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1"), + cel::AttributePattern("var2")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT( + result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"), cel::Attribute("var2"))); +} + +TEST_F(ModernUnknownTest, StructErrorUnknown) { + auto program = CreateProgram( + R"cel(cel.expr.conformance.proto3.TestAllTypes{single_int64: var1, single_uint64: 1u / 0u})cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + EXPECT_TRUE(result.IsError()); +} + +TEST_F(ModernUnknownTest, Variable) { + auto program = CreateProgram(R"cel(var1)cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern("var1")}), + IsOk()); + BindJsonToActivation("var1", R"json({})json"); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute("var1"))); +} + +TEST_F(ModernUnknownTest, ReturnPartiallyUnknownValue) { + // This is an unfortunate but existing bug that we should eventually fix. We + // return a partial unknown from evaluation. + auto program = CreateProgram(R"cel(var1)cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern( + "var1", {cel::AttributeQualifierPattern::Wildcard()})}), + IsOk()); + BindJsonToActivation("var1", R"json({})json"); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsMap()); +} + +TEST_F(ModernUnknownTest, MapVariableSelectStringQualifier) { + auto program = CreateProgram(R"cel(var1.k)cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern( + "var1", {cel::AttributeQualifierPattern::OfString("k")})}), + IsOk()); + BindJsonToActivation("var1", R"json({})json"); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute( + "var1", {cel::AttributeQualifier::OfString("k")}))); +} + +TEST_F(ModernUnknownTest, MapVariableSelectWildcardQualifier) { + auto program = CreateProgram(R"cel(var1.k)cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern( + "var1", {cel::AttributeQualifierPattern::Wildcard()})}), + IsOk()); + BindJsonToActivation("var1", R"json({})json"); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre(cel::Attribute( + "var1", {cel::AttributeQualifier::OfString("k")}))); +} + +TEST_F(ModernUnknownTest, ListVariableIndexIntQualifier) { + auto program = CreateProgram(R"cel(var1[0])cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern( + "var1", {cel::AttributeQualifierPattern::OfInt(0)})}), + IsOk()); + BindJsonToActivation("var1", R"json([])json"); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre( + cel::Attribute("var1", {cel::AttributeQualifier::OfInt(0)}))); +} + +TEST_F(ModernUnknownTest, ListVariableIndexWildcardQualifier) { + auto program = CreateProgram(R"cel(var1[0])cel"); + ASSERT_THAT(activation_.SetUnknownPatterns({cel::AttributePattern( + "var1", {cel::AttributeQualifierPattern::Wildcard()})}), + IsOk()); + BindJsonToActivation("var1", R"json([])json"); + ASSERT_OK_AND_ASSIGN(auto result, Evaluate(*program)); + ASSERT_TRUE(result.IsUnknown()); + EXPECT_THAT(result.GetUnknown().ToAttributeSet(), + UnorderedElementsAre( + cel::Attribute("var1", {cel::AttributeQualifier::OfInt(0)}))); +} + +} // namespace