blob: b9f6872529856846448bfc0b4db500d303e30d8d [file]
#include <string>
#include <gtest/gtest.h>
#include "testing/fuzzing/fuzztest.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);
upb_ExtensionRegistry_Add(ext_registry,
upb_test_ModelExtension1_model_ext_ext);
upb_ExtensionRegistry_Add(ext_registry,
upb_test_ModelExtension2_model_ext_ext);
upb_ExtensionRegistry_Add(ext_registry,
upb_test_ModelExtension2_model_ext_2_ext);
upb_ExtensionRegistry_Add(ext_registry,
upb_test_ModelExtension2_model_ext_3_ext);
upb_ExtensionRegistry_Add(ext_registry,
upb_test_ModelExtension2_model_ext_4_ext);
upb_ExtensionRegistry_Add(ext_registry,
upb_test_ModelExtension2_model_ext_5_ext);
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