mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
167 lines
6.2 KiB
C++
167 lines
6.2 KiB
C++
#include <string>
|
|
|
|
#include <gtest/gtest.h>
|
|
#include "testing/fuzzing/fuzztest.h"
|
|
#include "absl/base/throw_delegate.h"
|
|
#include "google/protobuf/util/message_differencer.h"
|
|
#include "upb/mem/arena.h"
|
|
#include "upb/message/compare.h"
|
|
#include "upb/message/message.h"
|
|
#include "upb/mini_table/extension_registry.h"
|
|
#include "upb/mini_table/message.h"
|
|
#include "upb/test/test.pb.h"
|
|
#include "upb/test/test.upb_minitable.h"
|
|
#include "upb/wire/decode.h"
|
|
|
|
namespace upb {
|
|
namespace {
|
|
|
|
const upb_ExtensionRegistry* CreateTestExtensionRegistry(upb_Arena* arena) {
|
|
upb_ExtensionRegistry* ext_registry = upb_ExtensionRegistry_New(arena);
|
|
if (upb_ExtensionRegistry_Add(ext_registry,
|
|
upb_test_ModelExtension1_model_ext_ext) !=
|
|
kUpb_ExtensionRegistryStatus_Ok) {
|
|
absl::ThrowStdBadAlloc();
|
|
}
|
|
if (upb_ExtensionRegistry_Add(ext_registry,
|
|
upb_test_ModelExtension2_model_ext_ext) !=
|
|
kUpb_ExtensionRegistryStatus_Ok) {
|
|
absl::ThrowStdBadAlloc();
|
|
}
|
|
if (upb_ExtensionRegistry_Add(ext_registry,
|
|
upb_test_ModelExtension2_model_ext_2_ext) !=
|
|
kUpb_ExtensionRegistryStatus_Ok) {
|
|
absl::ThrowStdBadAlloc();
|
|
}
|
|
if (upb_ExtensionRegistry_Add(ext_registry,
|
|
upb_test_ModelExtension2_model_ext_3_ext) !=
|
|
kUpb_ExtensionRegistryStatus_Ok) {
|
|
absl::ThrowStdBadAlloc();
|
|
}
|
|
if (upb_ExtensionRegistry_Add(ext_registry,
|
|
upb_test_ModelExtension2_model_ext_4_ext) !=
|
|
kUpb_ExtensionRegistryStatus_Ok) {
|
|
absl::ThrowStdBadAlloc();
|
|
}
|
|
if (upb_ExtensionRegistry_Add(ext_registry,
|
|
upb_test_ModelExtension2_model_ext_5_ext) !=
|
|
kUpb_ExtensionRegistryStatus_Ok) {
|
|
absl::ThrowStdBadAlloc();
|
|
}
|
|
return ext_registry;
|
|
}
|
|
|
|
template <typename T>
|
|
void ComparePartialEqualityProto(const upb_MiniTable* mini_table,
|
|
const upb_ExtensionRegistry* ext_registry,
|
|
const T& cpp_actual, const T& cpp_expected) {
|
|
std::string payload_actual = cpp_actual.SerializeAsString();
|
|
std::string payload_expected = cpp_expected.SerializeAsString();
|
|
|
|
// 1. C++ MessageDifferencer partial equality.
|
|
// MessageDifferencer::PARTIAL checks fields present in the first argument.
|
|
// UPB partial equality (upb_Message_IsEqual(actual, expected, ..., PARTIAL))
|
|
// checks fields present in expected (msg2).
|
|
// Therefore, cpp_expected is passed as the first argument.
|
|
google::protobuf::util::MessageDifferencer differencer;
|
|
differencer.set_scope(google::protobuf::util::MessageDifferencer::PARTIAL);
|
|
bool cpp_equals = differencer.Compare(cpp_expected, cpp_actual);
|
|
|
|
// 2. UPB partial equality.
|
|
upb_Arena* arena = upb_Arena_New();
|
|
|
|
upb_Message* upb_actual = upb_Message_New(mini_table, arena);
|
|
upb_Message* upb_expected = upb_Message_New(mini_table, arena);
|
|
|
|
upb_DecodeStatus status_actual =
|
|
upb_Decode(payload_actual.data(), payload_actual.size(), upb_actual,
|
|
mini_table, ext_registry, 0, arena);
|
|
upb_DecodeStatus status_expected =
|
|
upb_Decode(payload_expected.data(), payload_expected.size(), upb_expected,
|
|
mini_table, ext_registry, 0, arena);
|
|
|
|
ASSERT_EQ(status_actual, kUpb_DecodeStatus_Ok);
|
|
ASSERT_EQ(status_expected, kUpb_DecodeStatus_Ok);
|
|
|
|
bool upb_equals = upb_Message_IsEqual(upb_actual, upb_expected, mini_table,
|
|
kUpb_CompareOption_Partial);
|
|
|
|
EXPECT_EQ(upb_equals, cpp_equals)
|
|
<< "Mismatch between UPB and C++ partial equality!\n"
|
|
<< "cpp_equals: " << cpp_equals << ", upb_equals: " << upb_equals << "\n"
|
|
<< "cpp_actual: " << cpp_actual.DebugString() << "\n"
|
|
<< "cpp_expected: " << cpp_expected.DebugString();
|
|
|
|
upb_Arena_Free(arena);
|
|
}
|
|
|
|
void DifferentialPartialEqualsScalarFuzz(
|
|
const upb_test::HelloRequest& base_expected,
|
|
const upb_test::HelloRequest& extra_actual) {
|
|
upb_test::HelloRequest cpp_actual = base_expected;
|
|
cpp_actual.MergeFrom(extra_actual);
|
|
ComparePartialEqualityProto<upb_test::HelloRequest>(
|
|
&upb_0test__HelloRequest_msg_init, nullptr, cpp_actual, base_expected);
|
|
}
|
|
|
|
void DifferentialPartialEqualsMapFuzz(
|
|
const upb_test::ModelWithMaps& base_expected,
|
|
const upb_test::ModelWithMaps& extra_actual) {
|
|
upb_Arena* arena = upb_Arena_New();
|
|
const upb_ExtensionRegistry* ext_registry =
|
|
CreateTestExtensionRegistry(arena);
|
|
|
|
upb_test::ModelWithMaps cpp_actual = base_expected;
|
|
cpp_actual.MergeFrom(extra_actual);
|
|
ComparePartialEqualityProto<upb_test::ModelWithMaps>(
|
|
&upb_0test__ModelWithMaps_msg_init, ext_registry, cpp_actual,
|
|
base_expected);
|
|
|
|
upb_Arena_Free(arena);
|
|
}
|
|
|
|
void DifferentialPartialEqualsExtensionFuzz(
|
|
const upb_test::ModelWithExtensions& base_expected,
|
|
const upb_test::ModelWithExtensions& extra_actual) {
|
|
upb_test::ModelWithExtensions cpp_actual = base_expected;
|
|
cpp_actual.MergeFrom(extra_actual);
|
|
|
|
upb_Arena* arena = upb_Arena_New();
|
|
const upb_ExtensionRegistry* ext_registry =
|
|
CreateTestExtensionRegistry(arena);
|
|
|
|
ComparePartialEqualityProto<upb_test::ModelWithExtensions>(
|
|
&upb_0test__ModelWithExtensions_msg_init, ext_registry, cpp_actual,
|
|
base_expected);
|
|
|
|
upb_Arena_Free(arena);
|
|
}
|
|
|
|
FUZZ_TEST(CompareFuzzTest, DifferentialPartialEqualsScalarFuzz);
|
|
FUZZ_TEST(CompareFuzzTest, DifferentialPartialEqualsMapFuzz);
|
|
FUZZ_TEST(CompareFuzzTest, DifferentialPartialEqualsExtensionFuzz);
|
|
|
|
TEST(CompareFuzzTest, PartialMapComparisonExtraKeysInActual) {
|
|
upb_test::ModelWithMaps cpp_expected;
|
|
(*cpp_expected.mutable_map_ss())["k1"] = "v1";
|
|
|
|
upb_test::ModelWithMaps cpp_actual = cpp_expected;
|
|
(*cpp_actual.mutable_map_ss())["k2"] = "v2";
|
|
|
|
ComparePartialEqualityProto<upb_test::ModelWithMaps>(
|
|
&upb_0test__ModelWithMaps_msg_init, nullptr, cpp_actual, cpp_expected);
|
|
}
|
|
|
|
TEST(CompareFuzzTest, PartialPresenceFieldMissingInActual) {
|
|
upb_test::ModelWithExtensions cpp_expected;
|
|
cpp_expected.set_random_name(""); // Presence is set to default value.
|
|
|
|
upb_test::ModelWithExtensions cpp_actual; // Presence is NOT set in actual.
|
|
|
|
ComparePartialEqualityProto<upb_test::ModelWithExtensions>(
|
|
&upb_0test__ModelWithExtensions_msg_init, nullptr, cpp_actual,
|
|
cpp_expected);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace upb
|