From 387bae91178a0e98c3fffd4a6d4d4c8c8af8f3c0 Mon Sep 17 00:00:00 2001 From: Justin King Date: Thu, 5 Sep 2024 10:05:24 -0700 Subject: [PATCH] `ParsedMapFieldValue` stub out `MapValue` PiperOrigin-RevId: 671413590 --- common/values/parsed_map_field_value.cc | 136 +++++++++++++++++ common/values/parsed_map_field_value.h | 60 ++++++++ common/values/parsed_map_field_value_test.cc | 153 ++++++++++++++++++- 3 files changed, 348 insertions(+), 1 deletion(-) diff --git a/common/values/parsed_map_field_value.cc b/common/values/parsed_map_field_value.cc index 88819dd4d..c65ff5daf 100644 --- a/common/values/parsed_map_field_value.cc +++ b/common/values/parsed_map_field_value.cc @@ -13,3 +13,139 @@ // limitations under the License. #include "common/values/parsed_map_field_value.h" + +#include +#include +#include +#include + +#include "absl/base/nullability.h" +#include "absl/base/optimization.h" +#include "absl/log/absl_check.h" +#include "absl/log/die_if_null.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/cord.h" +#include "common/json.h" +#include "common/value.h" +#include "internal/status_macros.h" +#include "google/protobuf/message.h" + +namespace cel { + +std::string ParsedMapFieldValue::DebugString() const { + if (ABSL_PREDICT_FALSE(field_ == nullptr)) { + return "INVALID"; + } + return "VALID"; +} + +absl::Status ParsedMapFieldValue::SerializeTo(AnyToJsonConverter& converter, + absl::Cord& value) const { + return absl::UnimplementedError("SerializeTo is not yet implemented"); +} + +absl::StatusOr ParsedMapFieldValue::ConvertToJson( + AnyToJsonConverter& converter) const { + return absl::UnimplementedError("ConvertToJson is not yet implemented"); +} + +absl::StatusOr ParsedMapFieldValue::ConvertToJsonObject( + AnyToJsonConverter& converter) const { + return absl::UnimplementedError("ConvertToJsonObject is not yet implemented"); +} + +absl::Status ParsedMapFieldValue::Equal(ValueManager& value_manager, + const Value& other, + Value& result) const { + return absl::UnimplementedError("Equal is not yet implemented"); +} + +absl::StatusOr ParsedMapFieldValue::Equal(ValueManager& value_manager, + const Value& other) const { + Value result; + CEL_RETURN_IF_ERROR(Equal(value_manager, other, result)); + return result; +} + +bool ParsedMapFieldValue::IsZeroValue() const { return IsEmpty(); } + +bool ParsedMapFieldValue::IsEmpty() const { return Size() == 0; } + +size_t ParsedMapFieldValue::Size() const { + ABSL_DCHECK(*this); + if (ABSL_PREDICT_FALSE(field_ == nullptr)) { + return 0; + } + return static_cast( + GetReflectionOrDie()->FieldSize(*message_, field_)); +} + +absl::Status ParsedMapFieldValue::Get(ValueManager& value_manager, + const Value& key, Value& result) const { + return absl::UnimplementedError("Get is not yet implemented"); +} + +absl::StatusOr ParsedMapFieldValue::Get(ValueManager& value_manager, + const Value& key) const { + Value result; + CEL_RETURN_IF_ERROR(Get(value_manager, key, result)); + return result; +} + +absl::StatusOr ParsedMapFieldValue::Find(ValueManager& value_manager, + const Value& key, + Value& result) const { + return absl::UnimplementedError("Find is not yet implemented"); +} + +absl::StatusOr> ParsedMapFieldValue::Find( + ValueManager& value_manager, const Value& key) const { + Value result; + CEL_ASSIGN_OR_RETURN(auto found, Find(value_manager, key, result)); + if (found) { + return std::pair{std::move(result), found}; + } + return std::pair{NullValue(), found}; +} + +absl::Status ParsedMapFieldValue::Has(ValueManager& value_manager, + const Value& key, Value& result) const { + return absl::UnimplementedError("Has is not yet implemented"); +} + +absl::StatusOr ParsedMapFieldValue::Has(ValueManager& value_manager, + const Value& key) const { + Value result; + CEL_RETURN_IF_ERROR(Has(value_manager, key, result)); + return result; +} + +absl::Status ParsedMapFieldValue::ListKeys(ValueManager& value_manager, + ListValue& result) const { + return absl::UnimplementedError("ListKeys is not yet implemented"); +} + +absl::StatusOr ParsedMapFieldValue::ListKeys( + ValueManager& value_manager) const { + ListValue result; + CEL_RETURN_IF_ERROR(ListKeys(value_manager, result)); + return result; +} + +absl::Status ParsedMapFieldValue::ForEach(ValueManager& value_manager, + ForEachCallback callback) const { + return absl::UnimplementedError("ForEach is not yet implemented"); +} + +absl::StatusOr>> +ParsedMapFieldValue::NewIterator(ValueManager& value_manager) const { + return absl::UnimplementedError("NewIterator is not yet implemented"); +} + +absl::Nonnull +ParsedMapFieldValue::GetReflectionOrDie() const { + return ABSL_DIE_IF_NULL(message_->GetReflection()); // Crash OK +} + +} // namespace cel diff --git a/common/values/parsed_map_field_value.h b/common/values/parsed_map_field_value.h index 0c62e3d91..6e752fbf1 100644 --- a/common/values/parsed_map_field_value.h +++ b/common/values/parsed_map_field_value.h @@ -18,22 +18,33 @@ #ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_FIELD_VALUE_H_ #define THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_FIELD_VALUE_H_ +#include +#include +#include #include #include "google/protobuf/any.pb.h" #include "google/protobuf/struct.pb.h" #include "absl/base/nullability.h" #include "absl/log/absl_check.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/cord.h" #include "absl/strings/string_view.h" +#include "common/json.h" #include "common/memory.h" #include "common/type.h" #include "common/value_kind.h" +#include "common/values/map_value_interface.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/message.h" namespace cel { class Value; +class ValueManager; +class ValueIterator; +class ListValue; // ParsedMapFieldValue is a MapValue over a map field of a parsed protocol // buffer message. @@ -64,6 +75,53 @@ class ParsedMapFieldValue final { static MapType GetRuntimeType() { return MapType(); } + std::string DebugString() const; + + absl::Status SerializeTo(AnyToJsonConverter& converter, + absl::Cord& value) const; + + absl::StatusOr ConvertToJson(AnyToJsonConverter& converter) const; + + absl::StatusOr ConvertToJsonObject( + AnyToJsonConverter& converter) const; + + absl::Status Equal(ValueManager& value_manager, const Value& other, + Value& result) const; + absl::StatusOr Equal(ValueManager& value_manager, + const Value& other) const; + + bool IsZeroValue() const; + + bool IsEmpty() const; + + size_t Size() const; + + absl::Status Get(ValueManager& value_manager, const Value& key, + Value& result) const; + absl::StatusOr Get(ValueManager& value_manager, + const Value& key) const; + + absl::StatusOr Find(ValueManager& value_manager, const Value& key, + Value& result) const; + absl::StatusOr> Find(ValueManager& value_manager, + const Value& key) const; + + absl::Status Has(ValueManager& value_manager, const Value& key, + Value& result) const; + absl::StatusOr Has(ValueManager& value_manager, + const Value& key) const; + + absl::Status ListKeys(ValueManager& value_manager, ListValue& result) const; + absl::StatusOr ListKeys(ValueManager& value_manager) const; + + using ForEachCallback = typename MapValueInterface::ForEachCallback; + + absl::Status ForEach(ValueManager& value_manager, + ForEachCallback callback) const; + + absl::StatusOr>> NewIterator( + ValueManager& value_manager) const; + // Returns `true` if `ParsedMapFieldValue` is in a valid state. explicit operator bool() const { return field_ != nullptr; } @@ -75,6 +133,8 @@ class ParsedMapFieldValue final { } private: + absl::Nonnull GetReflectionOrDie() const; + Owned message_; absl::Nullable field_ = nullptr; }; diff --git a/common/values/parsed_map_field_value_test.cc b/common/values/parsed_map_field_value_test.cc index b6b71da75..a08145fc8 100644 --- a/common/values/parsed_map_field_value_test.cc +++ b/common/values/parsed_map_field_value_test.cc @@ -14,11 +14,18 @@ #include "absl/base/nullability.h" #include "absl/log/die_if_null.h" +#include "absl/status/status.h" +#include "absl/status/status_matchers.h" +#include "absl/status/statusor.h" +#include "absl/strings/cord.h" #include "absl/types/optional.h" #include "common/allocator.h" +#include "common/memory.h" #include "common/type.h" +#include "common/type_reflector.h" #include "common/value.h" #include "common/value_kind.h" +#include "common/value_manager.h" #include "internal/parse_text_proto.h" #include "internal/testing.h" #include "internal/testing_descriptor_pool.h" @@ -31,9 +38,11 @@ namespace cel { namespace { +using ::absl_testing::StatusIs; using ::cel::internal::DynamicParseTextProto; using ::cel::internal::GetTestingDescriptorPool; using ::cel::internal::GetTestingMessageFactory; +using ::testing::_; using ::testing::PrintToStringParamName; using ::testing::TestWithParam; @@ -45,13 +54,23 @@ class ParsedMapFieldValueTest : public TestWithParam { switch (GetParam()) { case AllocatorKind::kArena: arena_.emplace(); + value_manager_ = NewThreadCompatibleValueManager( + MemoryManager::Pooling(arena()), + NewThreadCompatibleTypeReflector(MemoryManager::Pooling(arena()))); break; case AllocatorKind::kNewDelete: + value_manager_ = NewThreadCompatibleValueManager( + MemoryManager::ReferenceCounting(), + NewThreadCompatibleTypeReflector( + MemoryManager::ReferenceCounting())); break; } } - void TearDown() override { arena_.reset(); } + void TearDown() override { + value_manager_.reset(); + arena_.reset(); + } Allocator<> allocator() { return arena_ ? ArenaAllocator(&*arena_) : NewDeleteAllocator(); @@ -67,8 +86,11 @@ class ParsedMapFieldValueTest : public TestWithParam { return GetTestingMessageFactory(); } + ValueManager& value_manager() { return **value_manager_; } + private: absl::optional arena_; + absl::optional> value_manager_; }; TEST_P(ParsedMapFieldValueTest, Default) { @@ -102,6 +124,135 @@ TEST_P(ParsedMapFieldValueTest, GetRuntimeType) { EXPECT_EQ(value.GetRuntimeType(), MapType()); } +TEST_P(ParsedMapFieldValueTest, DebugString) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.DebugString(), _); +} + +TEST_P(ParsedMapFieldValueTest, IsZeroValue) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_TRUE(valid_value.IsZeroValue()); +} + +TEST_P(ParsedMapFieldValueTest, SerializeTo) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + absl::Cord serialized; + EXPECT_THAT(valid_value.SerializeTo(value_manager(), serialized), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, ConvertToJson) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.ConvertToJson(value_manager()), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, Equal) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.Equal(value_manager(), BoolValue()), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, Empty) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_TRUE(valid_value.IsEmpty()); +} + +TEST_P(ParsedMapFieldValueTest, Size) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_EQ(valid_value.Size(), 0); +} + +TEST_P(ParsedMapFieldValueTest, Get) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.Get(value_manager(), BoolValue()), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, Find) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.Find(value_manager(), BoolValue()), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, Has) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.Has(value_manager(), BoolValue()), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, ListKeys) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.ListKeys(value_manager()), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, ForEach) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.ForEach(value_manager(), + [](const Value&, const Value&) + -> absl::StatusOr { return true; }), + StatusIs(absl::StatusCode::kUnimplemented)); +} + +TEST_P(ParsedMapFieldValueTest, NewIterator) { + auto message = DynamicParseTextProto( + allocator(), R"pb()pb", descriptor_pool(), message_factory()); + ParsedMapFieldValue valid_value( + message, ABSL_DIE_IF_NULL(message->GetDescriptor()->FindFieldByName( + "map_int64_int64"))); + EXPECT_THAT(valid_value.NewIterator(value_manager()), + StatusIs(absl::StatusCode::kUnimplemented)); +} + INSTANTIATE_TEST_SUITE_P(ParsedMapFieldValueTest, ParsedMapFieldValueTest, ::testing::Values(AllocatorKind::kArena, AllocatorKind::kNewDelete),