| #include <cstddef> | |
| #include <cstdio> | |
| #include <string> | |
| #include <vector> | |
| #include <gtest/gtest.h> | |
| #include "google/protobuf/test_messages_proto2.upb.h" | |
| #include "google/protobuf/test_messages_proto2.upb_minitable.h" | |
| #include "upb/base/string_view.h" | |
| #include "upb/base/upcast.h" | |
| #include "upb/mem/arena.h" | |
| #include "upb/message/compare.h" | |
| #include "upb/mini_table/message.h" | |
| #include "upb/wire/decode.h" | |
| #include "upb/wire/encode.h" | |
| namespace { | |
| static const upb_MiniTable* kTestMiniTable = | |
| &protobuf_0test_0messages__proto2__TestAllTypesProto2_msg_init; | |
| static void TestEncodeDecodeRoundTrip( | |
| upb_Arena* arena, | |
| std::vector<protobuf_test_messages_proto2_TestAllTypesProto2*> msgs) { | |
| // Encode all of the messages and put their serializations contiguously. | |
| std::string s; | |
| for (auto msg : msgs) { | |
| char* buf; | |
| size_t size; | |
| ASSERT_TRUE(upb_EncodeLengthPrefixed(UPB_UPCAST(msg), kTestMiniTable, 0, | |
| arena, &buf, | |
| &size) == kUpb_EncodeStatus_Ok); | |
| ASSERT_GT(size, 0u); // Even empty messages are 1 byte in this encoding. | |
| s.append(std::string(buf, size)); | |
| } | |
| // Now decode all of the messages contained in the contiguous block. | |
| std::vector<protobuf_test_messages_proto2_TestAllTypesProto2*> decoded; | |
| while (!s.empty()) { | |
| protobuf_test_messages_proto2_TestAllTypesProto2* msg = | |
| protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); | |
| size_t num_bytes_read; | |
| ASSERT_TRUE(upb_DecodeLengthPrefixed( | |
| s.data(), s.length(), UPB_UPCAST(msg), &num_bytes_read, | |
| kTestMiniTable, nullptr, 0, arena) == kUpb_DecodeStatus_Ok); | |
| ASSERT_GT(num_bytes_read, 0u); | |
| decoded.push_back(msg); | |
| s = s.substr(num_bytes_read); | |
| } | |
| // Make sure that the values round tripped correctly. | |
| ASSERT_EQ(msgs.size(), decoded.size()); | |
| for (size_t i = 0; i < msgs.size(); ++i) { | |
| ASSERT_TRUE(upb_Message_IsEqual(UPB_UPCAST(msgs[i]), UPB_UPCAST(decoded[i]), | |
| kTestMiniTable, 0)); | |
| } | |
| } | |
| TEST(LengthPrefixedTest, OneEmptyMessage) { | |
| upb_Arena* arena = upb_Arena_New(); | |
| protobuf_test_messages_proto2_TestAllTypesProto2* msg = | |
| protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); | |
| TestEncodeDecodeRoundTrip(arena, {msg}); | |
| upb_Arena_Free(arena); | |
| } | |
| TEST(LengthPrefixedTest, AFewMessages) { | |
| upb_Arena* arena = upb_Arena_New(); | |
| protobuf_test_messages_proto2_TestAllTypesProto2* a = | |
| protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); | |
| protobuf_test_messages_proto2_TestAllTypesProto2* b = | |
| protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); | |
| protobuf_test_messages_proto2_TestAllTypesProto2* c = | |
| protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); | |
| protobuf_test_messages_proto2_TestAllTypesProto2_set_optional_bool(a, true); | |
| protobuf_test_messages_proto2_TestAllTypesProto2_set_optional_int32(b, 1); | |
| protobuf_test_messages_proto2_TestAllTypesProto2_set_oneof_string( | |
| c, upb_StringView_FromString("string")); | |
| TestEncodeDecodeRoundTrip(arena, {a, b, c}); | |
| upb_Arena_Free(arena); | |
| } | |
| } // namespace |