Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
5.0 KiB
125 lines
5.0 KiB
// Protocol Buffers - Google's data interchange format |
|
// Copyright 2023 Google LLC. All rights reserved. |
|
// |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file or at |
|
// https://developers.google.com/open-source/licenses/bsd |
|
|
|
#ifndef UPB_UTIL_DEF_TO_PROTO_TEST_H_ |
|
#define UPB_UTIL_DEF_TO_PROTO_TEST_H_ |
|
|
|
#include <string> |
|
|
|
#include "google/protobuf/descriptor.pb.h" |
|
#include "google/protobuf/descriptor.upb.h" |
|
#include <gmock/gmock.h> |
|
#include <gtest/gtest.h> |
|
#include "google/protobuf/descriptor.h" |
|
#include "google/protobuf/dynamic_message.h" |
|
#include "google/protobuf/util/field_comparator.h" |
|
#include "upb/base/status.hpp" |
|
#include "upb/mem/arena.hpp" |
|
#include "upb/reflection/def.hpp" |
|
#include "upb/util/def_to_proto.h" |
|
|
|
namespace upb_test { |
|
|
|
// A gtest matcher that verifies that a proto is equal to `proto`. Both `proto` |
|
// and `arg` must be messages of type `msgdef_func` (a .upbdefs.h function that |
|
// loads a known msgdef into the given defpool). |
|
MATCHER_P(EqualsProtoTreatNansAsEqual, proto, |
|
negation ? "are not equal" : "are equal") { |
|
upb::DefPool defpool; |
|
google::protobuf::DescriptorPool pool; |
|
google::protobuf::DynamicMessageFactory factory; |
|
std::string differences; |
|
google::protobuf::util::DefaultFieldComparator comparator; |
|
comparator.set_treat_nan_as_equal(true); |
|
google::protobuf::util::MessageDifferencer differencer; |
|
differencer.set_field_comparator(&comparator); |
|
differencer.ReportDifferencesToString(&differences); |
|
bool eq = differencer.Compare(proto, arg); |
|
if (!eq) { |
|
*result_listener << differences; |
|
} |
|
return eq; |
|
} |
|
|
|
class NullErrorCollector : public google::protobuf::DescriptorPool::ErrorCollector { |
|
void RecordError(absl::string_view filename, absl::string_view element_name, |
|
const google::protobuf::Message* descriptor, ErrorLocation location, |
|
absl::string_view message) override {} |
|
void RecordWarning(absl::string_view filename, absl::string_view element_name, |
|
const google::protobuf::Message* descriptor, ErrorLocation location, |
|
absl::string_view message) override {} |
|
}; |
|
|
|
static void AddFile(google::protobuf::FileDescriptorProto& file, upb::DefPool* pool, |
|
google::protobuf::DescriptorPool* desc_pool) { |
|
NullErrorCollector collector; |
|
const google::protobuf::FileDescriptor* file_desc = |
|
desc_pool->BuildFileCollectingErrors(file, &collector); |
|
|
|
if (file_desc != nullptr) { |
|
// The file descriptor was valid according to proto2. |
|
google::protobuf::FileDescriptorProto normalized_file; |
|
file_desc->CopyTo(&normalized_file); |
|
std::string serialized; |
|
normalized_file.SerializeToString(&serialized); |
|
upb::Arena arena; |
|
upb::Status status; |
|
google_protobuf_FileDescriptorProto* proto = google_protobuf_FileDescriptorProto_parse( |
|
serialized.data(), serialized.size(), arena.ptr()); |
|
ASSERT_NE(proto, nullptr); |
|
upb::FileDefPtr file_def = pool->AddFile(proto, &status); |
|
|
|
// Ideally we could assert that file_def is present here. After all, any |
|
// descriptor accepted by C++ should be by definition valid. However C++ |
|
// performs some of its validation at the .proto file parser level instead |
|
// of when validating descriptors. As as result, C++ will accept some |
|
// unreasonable descriptors like: |
|
// file { name: "" package: "0" } |
|
// |
|
// There is no .proto file that will produce this descriptor, but |
|
// BuildFile() accepts it. We should probably clean up these cases so C++ |
|
// will reject them too. |
|
if (!file_def) return; |
|
|
|
ASSERT_TRUE(status.ok()) << status.error_message(); |
|
google_protobuf_FileDescriptorProto* upb_proto = |
|
upb_FileDef_ToProto(file_def.ptr(), arena.ptr()); |
|
size_t size; |
|
const char* buf = |
|
google_protobuf_FileDescriptorProto_serialize(upb_proto, arena.ptr(), &size); |
|
google::protobuf::FileDescriptorProto google_proto; |
|
bool ok = google_proto.ParseFromArray(buf, size); |
|
ASSERT_TRUE(ok); |
|
EXPECT_THAT(google_proto, EqualsProtoTreatNansAsEqual(normalized_file)); |
|
} else { |
|
// This file was invalid according to proto2. When we parse it with upb, |
|
// it may or may not be accepted, since upb does not perform as much |
|
// validation as proto2. However it must not crash. |
|
std::string serialized; |
|
file.SerializeToString(&serialized); |
|
upb::Arena arena; |
|
upb::Status status; |
|
google_protobuf_FileDescriptorProto* proto = google_protobuf_FileDescriptorProto_parse( |
|
serialized.data(), serialized.size(), arena.ptr()); |
|
ASSERT_NE(proto, nullptr); |
|
pool->AddFile(proto, &status); |
|
} |
|
} |
|
|
|
inline void RoundTripDescriptor(const google::protobuf::FileDescriptorSet& set) { |
|
upb::DefPool defpool; |
|
google::protobuf::DescriptorPool desc_pool; |
|
desc_pool.EnforceWeakDependencies(true); |
|
for (const auto& file : set.file()) { |
|
google::protobuf::FileDescriptorProto mutable_file(file); |
|
AddFile(mutable_file, &defpool, &desc_pool); |
|
} |
|
} |
|
|
|
} // namespace upb_test |
|
|
|
#endif // UPB_UTIL_DEF_TO_PROTO_TEST_H_
|
|
|