Skip to content

Commit

Permalink
Add a matcher to test cel::StructValue against a protobuf message.
Browse files Browse the repository at this point in the history
This facilitates testing the content of a StructValue when its type matches a protobuf message, instead of testing every individual field.

Example usage:

ASSERT_THAT(l, StructValueAsProto<MyMessage>(EqualsProto("my_int: 42")));

PiperOrigin-RevId: 646191570
  • Loading branch information
seirl authored and copybara-github committed Jun 25, 2024
1 parent 123a35c commit 6dfc7d5
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
30 changes: 30 additions & 0 deletions extensions/protobuf/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,33 @@ cc_test(
"@com_google_protobuf//:protobuf",
],
)

cc_library(
name = "value_testing",
testonly = True,
hdrs = ["value_testing.h"],
deps = [
":value",
"//common:value",
"//extensions/protobuf/internal:message",
"//internal:testing",
"@com_google_absl//absl/status",
],
)

cc_test(
name = "value_testing_test",
srcs = ["value_testing_test.cc"],
deps = [
":memory_manager",
":value",
":value_testing",
"//common:memory",
"//common:value",
"//common:value_testing",
"//internal:proto_matchers",
"//internal:testing",
"@com_google_cel_spec//proto/test/v1/proto2:test_all_types_cc_proto",
"@com_google_protobuf//:protobuf",
],
)
78 changes: 78 additions & 0 deletions extensions/protobuf/value_testing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2024 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.

#ifndef THIRD_PARTY_CEL_CPP_EXTENSIONS_PROTOBUF_VALUE_TESTING_H_
#define THIRD_PARTY_CEL_CPP_EXTENSIONS_PROTOBUF_VALUE_TESTING_H_

#include <ostream>

#include "absl/status/status.h"
#include "common/value.h"
#include "extensions/protobuf/internal/message.h"
#include "extensions/protobuf/value.h"
#include "internal/testing.h"

namespace cel::extensions::test {

template <typename MessageType>
class StructValueAsProtoMatcher {
public:
using is_gtest_matcher = void;

explicit StructValueAsProtoMatcher(testing::Matcher<MessageType>&& m)
: m_(std::move(m)) {}

bool MatchAndExplain(cel::Value v,
testing::MatchResultListener* result_listener) const {
MessageType msg;
absl::Status s = ProtoMessageFromValue(v, msg);
if (!s.ok()) {
*result_listener << "cannot convert to "
<< MessageType::descriptor()->full_name() << ": " << s;
return false;
}
return m_.MatchAndExplain(msg, result_listener);
}

void DescribeTo(std::ostream* os) const {
*os << "matches proto message " << m_;
}

void DescribeNegationTo(std::ostream* os) const {
*os << "does not match proto message " << m_;
}

private:
testing::Matcher<MessageType> m_;
};

// Returns a matcher that matches a cel::Value against a proto message.
//
// Example usage:
//
// EXPECT_THAT(value, StructValueAsProto<TestAllTypes>(EqualsProto(R"pb(
// single_int32: 1
// single_string: "foo"
// )pb")));
template <typename MessageType>
inline StructValueAsProtoMatcher<MessageType> StructValueAsProto(
testing::Matcher<MessageType>&& m) {
static_assert(
cel::extensions::protobuf_internal::IsProtoMessage<MessageType>);
return StructValueAsProtoMatcher<MessageType>(std::move(m));
}

} // namespace cel::extensions::test

#endif // THIRD_PARTY_CEL_CPP_EXTENSIONS_PROTOBUF_VALUE_TESTING_H_
65 changes: 65 additions & 0 deletions extensions/protobuf/value_testing_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2024 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 "extensions/protobuf/value_testing.h"

#include "common/memory.h"
#include "common/value.h"
#include "common/value_testing.h"
#include "extensions/protobuf/memory_manager.h"
#include "extensions/protobuf/value.h"
#include "internal/proto_matchers.h"
#include "internal/testing.h"
#include "proto/test/v1/proto2/test_all_types.pb.h"
#include "google/protobuf/arena.h"

namespace cel::extensions::test {
namespace {

using ::cel::extensions::ProtoMessageToValue;
using ::cel::internal::test::EqualsProto;
using ::google::api::expr::test::v1::proto2::TestAllTypes;

class ProtoValueTesting : public common_internal::ThreadCompatibleValueTest<> {
protected:
MemoryManager NewThreadCompatiblePoolingMemoryManager() override {
return cel::extensions::ProtoMemoryManager(&arena_);
}

private:
google::protobuf::Arena arena_;
};

class ProtoValueTestingTest : public ProtoValueTesting {};

TEST_P(ProtoValueTestingTest, StructValueAsProtoSimple) {
TestAllTypes test_proto;
test_proto.set_single_int32(42);
test_proto.set_single_string("foo");

ASSERT_OK_AND_ASSIGN(cel::Value v,
ProtoMessageToValue(value_manager(), test_proto));
EXPECT_THAT(v, StructValueAsProto<TestAllTypes>(EqualsProto(R"pb(
single_int32: 42
single_string: "foo"
)pb")));
}

INSTANTIATE_TEST_SUITE_P(ProtoValueTesting, ProtoValueTestingTest,
testing::Values(MemoryManagement::kPooling,
MemoryManagement::kReferenceCounting),
ProtoValueTestingTest::ToString);

} // namespace
} // namespace cel::extensions::test

0 comments on commit 6dfc7d5

Please # to comment.