Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ParsedMapFieldValue stub out MapValue #899

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
ParsedMapFieldValue stub out MapValue
PiperOrigin-RevId: 671739325
jcking authored and copybara-github committed Sep 6, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 137a8cc4aa9a9298860fedde26f007c0d090e262
136 changes: 136 additions & 0 deletions common/values/parsed_map_field_value.cc
Original file line number Diff line number Diff line change
@@ -13,3 +13,139 @@
// limitations under the License.

#include "common/values/parsed_map_field_value.h"

#include <cstddef>
#include <memory>
#include <string>
#include <utility>

#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<Json> ParsedMapFieldValue::ConvertToJson(
AnyToJsonConverter& converter) const {
return absl::UnimplementedError("ConvertToJson is not yet implemented");
}

absl::StatusOr<JsonObject> 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<Value> 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<size_t>(
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<Value> ParsedMapFieldValue::Get(ValueManager& value_manager,
const Value& key) const {
Value result;
CEL_RETURN_IF_ERROR(Get(value_manager, key, result));
return result;
}

absl::StatusOr<bool> ParsedMapFieldValue::Find(ValueManager& value_manager,
const Value& key,
Value& result) const {
return absl::UnimplementedError("Find is not yet implemented");
}

absl::StatusOr<std::pair<Value, bool>> 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<Value> 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<ListValue> 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<absl::Nonnull<std::unique_ptr<ValueIterator>>>
ParsedMapFieldValue::NewIterator(ValueManager& value_manager) const {
return absl::UnimplementedError("NewIterator is not yet implemented");
}

absl::Nonnull<const google::protobuf::Reflection*>
ParsedMapFieldValue::GetReflectionOrDie() const {
return ABSL_DIE_IF_NULL(message_->GetReflection()); // Crash OK
}

} // namespace cel
60 changes: 60 additions & 0 deletions common/values/parsed_map_field_value.h
Original file line number Diff line number Diff line change
@@ -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 <cstddef>
#include <memory>
#include <string>
#include <utility>

#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<Json> ConvertToJson(AnyToJsonConverter& converter) const;

absl::StatusOr<JsonObject> ConvertToJsonObject(
AnyToJsonConverter& converter) const;

absl::Status Equal(ValueManager& value_manager, const Value& other,
Value& result) const;
absl::StatusOr<Value> 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<Value> Get(ValueManager& value_manager,
const Value& key) const;

absl::StatusOr<bool> Find(ValueManager& value_manager, const Value& key,
Value& result) const;
absl::StatusOr<std::pair<Value, bool>> Find(ValueManager& value_manager,
const Value& key) const;

absl::Status Has(ValueManager& value_manager, const Value& key,
Value& result) const;
absl::StatusOr<Value> Has(ValueManager& value_manager,
const Value& key) const;

absl::Status ListKeys(ValueManager& value_manager, ListValue& result) const;
absl::StatusOr<ListValue> ListKeys(ValueManager& value_manager) const;

using ForEachCallback = typename MapValueInterface::ForEachCallback;

absl::Status ForEach(ValueManager& value_manager,
ForEachCallback callback) const;

absl::StatusOr<absl::Nonnull<std::unique_ptr<ValueIterator>>> 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<const google::protobuf::Reflection*> GetReflectionOrDie() const;

Owned<const google::protobuf::Message> message_;
absl::Nullable<const google::protobuf::FieldDescriptor*> field_ = nullptr;
};
153 changes: 152 additions & 1 deletion common/values/parsed_map_field_value_test.cc
Original file line number Diff line number Diff line change
@@ -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<AllocatorKind> {
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<AllocatorKind> {
return GetTestingMessageFactory();
}

ValueManager& value_manager() { return **value_manager_; }

private:
absl::optional<google::protobuf::Arena> arena_;
absl::optional<Shared<ValueManager>> 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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<TestAllTypesProto3>(
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<bool> { return true; }),
StatusIs(absl::StatusCode::kUnimplemented));
}

TEST_P(ParsedMapFieldValueTest, NewIterator) {
auto message = DynamicParseTextProto<TestAllTypesProto3>(
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),