blob: 7e0a902721cab018a4854ed2d526239fad62221e [file] [log] [blame]
#include <string>
#include <string_view>
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.upb.h"
#include <gtest/gtest.h>
#include "absl/log/absl_check.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "upb/base/status.hpp"
#include "upb/mem/arena.hpp"
#include "upb/reflection/def.hpp"
#include "upb/test/parse_text_proto.h"
namespace upb_test {
namespace {
google_protobuf_FileDescriptorProto* ToUpbDescriptorSet(
const google::protobuf::FileDescriptorProto& proto, upb::Arena& arena) {
std::string serialized;
(void)proto.SerializeToString(&serialized);
return google_protobuf_FileDescriptorProto_parse(serialized.data(), serialized.size(),
arena.ptr());
}
absl::StatusOr<upb::DefPool> LoadDescriptorSetFromProto(
const google::protobuf::FileDescriptorSet& set) {
upb::Arena arena;
upb::DefPool defpool;
upb::Status status;
for (const auto& file : set.file()) {
google_protobuf_FileDescriptorProto* upb_proto = ToUpbDescriptorSet(file, arena);
ABSL_CHECK(upb_proto);
upb::FileDefPtr file_def = defpool.AddFile(upb_proto, &status);
if (!file_def) return absl::InternalError(status.error_message());
}
return defpool;
}
absl::StatusOr<upb::DefPool> LoadDescriptorProto(absl::string_view proto_text) {
google::protobuf::FileDescriptorProto proto = ParseTextProtoOrDie(proto_text);
google::protobuf::FileDescriptorSet set;
*set.add_file() = proto;
return LoadDescriptorSetFromProto(set);
}
TEST(ReflectionTest, OpenEnumWithNonZeroDefault) {
absl::Status status = LoadDescriptorProto(
R"pb(
syntax: "proto3"
name: "F"
enum_type {
name: "BadEnum"
value { name: "v1" number: 1 }
}
)pb")
.status();
EXPECT_EQ(std::string_view(status.message()),
"for open enums, the first value must be zero (BadEnum)");
}
TEST(ReflectionTest, EnumDefault) {
upb::DefPool pool = LoadDescriptorProto(
R"pb(
syntax: "proto2"
name: "F"
enum_type {
name: "FooEnum"
value { name: "v1" number: 1 }
}
)pb")
.value();
upb::EnumDefPtr e = pool.FindEnumByName("FooEnum");
EXPECT_EQ(e.default_value(), 1);
}
TEST(ReflectionTest, ImplicitPresenceWithDefault) {
absl::Status status =
LoadDescriptorProto(
R"pb(
syntax: "editions"
edition: EDITION_2023
name: "F"
message_type {
name: "FooMessage"
field {
name: "f1"
number: 1
type: TYPE_INT32
default_value: "1"
options { features { field_presence: IMPLICIT } }
}
}
)pb")
.status();
EXPECT_EQ(std::string_view(status.message()),
"fields with implicit presence cannot have explicit defaults "
"(FooMessage.f1)");
}
TEST(ReflectionTest, ImplicitPresenceWithNonZeroDefaultEnum) {
absl::Status status =
LoadDescriptorProto(
R"pb(
syntax: "editions"
edition: EDITION_2023
name: "F"
enum_type {
name: "FooEnum"
value { name: "v1" number: 1 }
options { features { enum_type: CLOSED } }
}
message_type {
name: "FooMessage"
field {
name: "f1"
number: 1
type: TYPE_ENUM
type_name: "FooEnum"
options { features { field_presence: IMPLICIT } }
}
}
)pb")
.status();
EXPECT_EQ(std::string_view(status.message()),
"Implicit presence field (FooMessage.f1) cannot use an enum type "
"with a non-zero default (FooEnum)");
}
} // namespace
} // namespace upb_test