1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <limits>
18 #include <memory>
19 #include <vector>
20 
21 #include "perfetto/protozero/message_handle.h"
22 #include "perfetto/protozero/packed_repeated_fields.h"
23 #include "test/gtest_and_gmock.h"
24 
25 // Autogenerated headers in out/*/gen/
26 #include "src/protozero/test/example_proto/library.gen.h"
27 #include "src/protozero/test/example_proto/test_messages.gen.h"
28 #include "src/protozero/test/example_proto/test_messages.pb.h"
29 
30 // Generated by the cppgen compiler.
31 namespace pbtest = protozero::test::protos::gen;
32 
33 // Generated by the official protobuf compiler.
34 namespace pbgold = protozero::test::protos;
35 
36 namespace protozero {
37 namespace {
38 
39 using testing::ElementsAreArray;
40 
41 // The two functions below are templated because they are re-used both on the
42 // libprotobuf and protozero versions to check both libproto -> zero and
43 // zero -> libproto compatibility.
44 template <typename T>
SetTestingFields(T * msg)45 void SetTestingFields(T* msg) {
46   msg->set_field_int32(-1);
47   msg->set_field_int64(-333123456789ll);
48   msg->set_field_uint32(600);
49   msg->set_field_uint64(333123456789ll);
50   msg->set_field_sint32(-5);
51   msg->set_field_sint64(-9000);
52   msg->set_field_fixed32(12345);
53   msg->set_field_fixed64(444123450000ll);
54   msg->set_field_sfixed32(-69999);
55   msg->set_field_sfixed64(-200);
56   msg->set_field_float(3.14f);
57   msg->set_field_double(0.5555);
58   msg->set_field_bool(true);
59 
60   msg->set_small_enum(decltype(msg->small_enum())::TO_BE);
61   msg->set_signed_enum(decltype(msg->signed_enum())::NEGATIVE);
62   msg->set_big_enum(decltype(msg->big_enum())::BEGIN);
63 
64   msg->set_field_string("FizzBuzz");
65   msg->set_field_bytes(reinterpret_cast<const uint8_t*>("\x11\x00\xBE\xEF"), 4);
66   msg->add_repeated_int32(1);
67   msg->add_repeated_int32(-1);
68   msg->add_repeated_int32(100);
69   msg->add_repeated_int32(2000000);
70 }
71 
72 template <typename T>
CheckTestingFields(const T & msg)73 void CheckTestingFields(const T& msg) {
74   EXPECT_EQ(-1, msg.field_int32());
75   EXPECT_EQ(-333123456789ll, msg.field_int64());
76   EXPECT_EQ(600u, msg.field_uint32());
77   EXPECT_EQ(333123456789ull, msg.field_uint64());
78   EXPECT_EQ(-5, msg.field_sint32());
79   EXPECT_EQ(-9000, msg.field_sint64());
80   EXPECT_EQ(12345u, msg.field_fixed32());
81   EXPECT_EQ(444123450000ull, msg.field_fixed64());
82   EXPECT_EQ(-69999, msg.field_sfixed32());
83   EXPECT_EQ(-200, msg.field_sfixed64());
84   EXPECT_FLOAT_EQ(3.14f, msg.field_float());
85   EXPECT_DOUBLE_EQ(0.5555, msg.field_double());
86   EXPECT_EQ(true, msg.field_bool());
87   EXPECT_EQ(decltype(msg.small_enum())::TO_BE, msg.small_enum());
88   EXPECT_EQ(decltype(msg.signed_enum())::NEGATIVE, msg.signed_enum());
89   EXPECT_EQ(decltype(msg.big_enum())::BEGIN, msg.big_enum());
90   EXPECT_EQ("FizzBuzz", msg.field_string());
91   EXPECT_EQ(std::string("\x11\x00\xBE\xEF", 4), msg.field_bytes());
92   ASSERT_THAT(msg.repeated_int32(), ElementsAreArray({1, -1, 100, 2000000}));
93 }
94 
TEST(ProtoCppConformanceTest,GenEncode_GoldDecode)95 TEST(ProtoCppConformanceTest, GenEncode_GoldDecode) {
96   pbtest::EveryField msg;
97   SetTestingFields(&msg);
98   std::string serialized = msg.SerializeAsString();
99 
100   pbgold::EveryField gold_msg;
101   gold_msg.ParseFromString(serialized);
102   CheckTestingFields(gold_msg);
103   EXPECT_EQ(serialized.size(), static_cast<size_t>(gold_msg.ByteSize()));
104 }
105 
TEST(ProtoCppConformanceTest,GoldEncode_GenDecode)106 TEST(ProtoCppConformanceTest, GoldEncode_GenDecode) {
107   pbgold::EveryField gold_msg;
108   SetTestingFields(&gold_msg);
109   std::string serialized = gold_msg.SerializeAsString();
110 
111   pbtest::EveryField msg;
112   EXPECT_TRUE(msg.ParseFromString(serialized));
113   CheckTestingFields(msg);
114 }
115 
TEST(ProtoCppConformanceTest,GenEncode_GenDecode)116 TEST(ProtoCppConformanceTest, GenEncode_GenDecode) {
117   pbtest::EveryField msg;
118   SetTestingFields(&msg);
119   std::string serialized = msg.SerializeAsString();
120 
121   pbtest::EveryField dec_msg;
122   dec_msg.ParseFromString(serialized);
123   CheckTestingFields(dec_msg);
124   EXPECT_EQ(serialized.size(), dec_msg.SerializeAsString().size());
125 }
126 
TEST(ProtoCppConformanceTest,NestedMessages)127 TEST(ProtoCppConformanceTest, NestedMessages) {
128   pbtest::NestedA msg_a;
129   pbtest::NestedA::NestedB* msg_b = msg_a.add_repeated_a();
130   pbtest::NestedA::NestedB::NestedC* msg_c = msg_b->mutable_value_b();
131   msg_c->set_value_c(321);
132   msg_b = msg_a.add_repeated_a();
133   msg_a.mutable_super_nested()->set_value_c(1000);
134   std::string serialized = msg_a.SerializeAsString();
135 
136   pbgold::NestedA gold_msg_a;
137   gold_msg_a.ParseFromString(serialized);
138   EXPECT_EQ(2, gold_msg_a.repeated_a_size());
139   EXPECT_EQ(321, gold_msg_a.repeated_a(0).value_b().value_c());
140   EXPECT_FALSE(gold_msg_a.repeated_a(1).has_value_b());
141   EXPECT_EQ(gold_msg_a.repeated_a(1).value_b().value_c(), 0);
142   EXPECT_EQ(1000, gold_msg_a.super_nested().value_c());
143 }
144 
145 // Tests that unknown fields are preserved when re-serializing. This test uses
146 // the messages NestedA and NestedA_V2, where NestedA_V2 mimics a future
147 // extension of NestedA. It starts filling the V2 version, than decodes it with
148 // V1, then re-encodes V1 and decodes with V2 and finally check that all the V2
149 // original fields have been preserved.
TEST(ProtoCppConformanceTest,PreserveUnknownFields)150 TEST(ProtoCppConformanceTest, PreserveUnknownFields) {
151   std::string serialized;
152   {
153     pbtest::TestVersioning_V2 msg_v2;
154     msg_v2.set_root_int(10);
155     msg_v2.set_root_int_v2(11);
156     msg_v2.add_enumz(pbtest::TestVersioning_V2::ONE);
157     msg_v2.add_enumz(pbtest::TestVersioning_V2::TWO);
158     msg_v2.add_enumz(pbtest::TestVersioning_V2::THREE_V2);
159     msg_v2.set_root_string("root-string");
160     msg_v2.add_rep_string("root-rep-string-1");
161     msg_v2.add_rep_string("root-rep-string-2");
162     for (int i = 0; i < 3; i++) {
163       auto* sub1 = i == 0 ? msg_v2.mutable_sub1() : msg_v2.add_sub1_rep();
164       sub1->set_sub1_int(12);
165       sub1->set_sub1_string("sub1-string");
166       sub1->set_sub1_int_v2(13);
167       sub1->set_sub1_string_v2("sub1-string-v2");
168 
169       auto* sub2 = i == 0 ? msg_v2.mutable_sub2() : msg_v2.add_sub2_rep();
170       sub2->set_sub2_int(14);
171       sub2->set_sub2_string("sub2-string");
172     }
173     {
174       pbtest::TestVersioning_V2::Sub1_V2 lazy;
175       lazy.set_sub1_int(15);
176       lazy.set_sub1_string("sub1-lazy-string");
177       lazy.set_sub1_int_v2(16);
178       lazy.set_sub1_string_v2("sub1-lazy-string-v2");
179       msg_v2.set_sub1_lazy_raw(lazy.SerializeAsString());
180     }
181     {
182       pbtest::TestVersioning_V2::Sub2_V2 lazy;
183       lazy.set_sub2_int(17);
184       lazy.set_sub2_string("sub2-v2-lazy-string");
185       msg_v2.set_sub2_lazy_raw(lazy.SerializeAsString());
186     }
187 
188     serialized = msg_v2.SerializeAsString();
189   }
190 
191   // Now decode with an earlier version that has less fields. Then re-serialize
192   // the v1 message.
193   {
194     pbtest::TestVersioning_V1 msg_v1;
195     EXPECT_TRUE(msg_v1.ParseFromString(serialized));
196     EXPECT_EQ(msg_v1.root_int(), 10);
197     EXPECT_EQ(msg_v1.enumz_size(), 3);
198     // These are to workaround "ODR-usage" rules that would require that the
199     // constexpr in the .gen.h file have a matching symbol definition in the .cc
200     // file.
201     const auto ONE = pbtest::TestVersioning_V1::ONE;
202     const auto TWO = pbtest::TestVersioning_V1::TWO;
203     EXPECT_EQ(msg_v1.enumz()[0], ONE);
204     EXPECT_EQ(msg_v1.enumz()[1], TWO);
205     EXPECT_EQ(static_cast<int>(msg_v1.enumz()[2]), 3);
206     EXPECT_EQ(msg_v1.root_string(), "root-string");
207     EXPECT_EQ(msg_v1.rep_string_size(), 2);
208     EXPECT_EQ(msg_v1.rep_string()[0], "root-rep-string-1");
209     EXPECT_EQ(msg_v1.rep_string()[1], "root-rep-string-2");
210     EXPECT_EQ(msg_v1.sub1_rep_size(), 2);
211     for (size_t i = 0; i < 3; i++) {
212       auto* sub1 = i == 0 ? &msg_v1.sub1() : &msg_v1.sub1_rep()[i - 1];
213       EXPECT_EQ(sub1->sub1_int(), 12);
214       EXPECT_EQ(sub1->sub1_string(), "sub1-string");
215     }
216 
217     // Append an extra field and change the valaue of an existing one before
218     // re-serializing.
219     msg_v1.set_root_int(101);
220     msg_v1.add_rep_string("extra-string");
221     serialized = msg_v1.SerializeAsString();
222   }
223 
224   // Decode the re-serialized v1 message with with v2. Check that the _v2
225   // fields have been preserved in the double de/serializataion across versions.
226   {
227     pbtest::TestVersioning_V2 msg_v2;
228     EXPECT_TRUE(msg_v2.ParseFromString(serialized));
229     EXPECT_EQ(msg_v2.root_int(), 101);
230     EXPECT_EQ(msg_v2.root_int_v2(), 11);
231     EXPECT_EQ(msg_v2.enumz_size(), 3);
232     const auto ONE = pbtest::TestVersioning_V2::ONE;
233     const auto TWO = pbtest::TestVersioning_V2::TWO;
234     const auto THREE_V2 = pbtest::TestVersioning_V2::THREE_V2;
235     EXPECT_EQ(msg_v2.enumz()[0], ONE);
236     EXPECT_EQ(msg_v2.enumz()[1], TWO);
237     EXPECT_EQ(msg_v2.enumz()[2], THREE_V2);
238     EXPECT_EQ(msg_v2.root_string(), "root-string");
239     EXPECT_EQ(msg_v2.rep_string_size(), 3);
240     EXPECT_EQ(msg_v2.rep_string()[0], "root-rep-string-1");
241     EXPECT_EQ(msg_v2.rep_string()[1], "root-rep-string-2");
242     EXPECT_EQ(msg_v2.rep_string()[2], "extra-string");
243     EXPECT_EQ(msg_v2.sub1_rep_size(), 2);
244     for (size_t i = 0; i < 3; i++) {
245       auto* sub1 = i == 0 ? &msg_v2.sub1() : &msg_v2.sub1_rep()[i - 1];
246       EXPECT_EQ(sub1->sub1_int(), 12);
247       EXPECT_EQ(sub1->sub1_string(), "sub1-string");
248       EXPECT_EQ(sub1->sub1_int_v2(), 13);
249       EXPECT_EQ(sub1->sub1_string_v2(), "sub1-string-v2");
250       auto* sub2 = i == 0 ? &msg_v2.sub2() : &msg_v2.sub2_rep()[i - 1];
251       EXPECT_EQ(sub2->sub2_int(), 14);
252       EXPECT_EQ(sub2->sub2_string(), "sub2-string");
253     }
254     {
255       pbtest::TestVersioning_V2::Sub1_V2 lazy;
256       EXPECT_TRUE(lazy.ParseFromString(msg_v2.sub1_lazy_raw()));
257       EXPECT_EQ(lazy.sub1_int(), 15);
258       EXPECT_EQ(lazy.sub1_string(), "sub1-lazy-string");
259       EXPECT_EQ(lazy.sub1_int_v2(), 16);
260       EXPECT_EQ(lazy.sub1_string_v2(), "sub1-lazy-string-v2");
261     }
262     {
263       pbtest::TestVersioning_V2::Sub2_V2 lazy;
264       EXPECT_TRUE(lazy.ParseFromString(msg_v2.sub2_lazy_raw()));
265       EXPECT_EQ(lazy.sub2_int(), 17);
266       EXPECT_EQ(lazy.sub2_string(), "sub2-v2-lazy-string");
267     }
268   }
269 }
270 
271 // Checks that unset fields aren't zero-initialized in the decode -> re-encode
272 // process.
TEST(ProtoCppConformanceTest,DontDefaultInitialize)273 TEST(ProtoCppConformanceTest, DontDefaultInitialize) {
274   pbtest::EveryField msg;
275   EXPECT_FALSE(msg.has_field_int32());
276   msg.set_field_int32(0);
277   EXPECT_TRUE(msg.has_field_int32());
278 
279   EXPECT_FALSE(msg.has_field_float());
280   msg.set_field_float(.0f);
281   EXPECT_TRUE(msg.has_field_float());
282 
283   EXPECT_FALSE(msg.has_field_string());
284   msg.set_field_string("");
285   EXPECT_TRUE(msg.has_field_string());
286 
287   pbtest::EveryField dec;
288   dec.ParseFromString(msg.SerializeAsString());
289   std::string reserialized = dec.SerializeAsString();
290 
291   pbgold::EveryField gold_msg;
292   gold_msg.ParseFromString(reserialized);
293   EXPECT_TRUE(gold_msg.has_field_int32());
294   EXPECT_EQ(gold_msg.field_int32(), 0);
295   EXPECT_TRUE(gold_msg.has_field_float());
296   EXPECT_FLOAT_EQ(gold_msg.field_float(), .0f);
297   EXPECT_TRUE(gold_msg.has_field_string());
298   EXPECT_EQ(gold_msg.field_string(), "");
299   EXPECT_FALSE(gold_msg.has_field_int64());
300   EXPECT_FALSE(gold_msg.has_field_uint64());
301   EXPECT_FALSE(gold_msg.has_field_bytes());
302 }
303 
304 // Tests serialization and deserialization of packed encoding fields.
TEST(ProtoCppConformanceTest,PackedRepeatedFields)305 TEST(ProtoCppConformanceTest, PackedRepeatedFields) {
306   std::string serialized;
307   {
308     pbtest::PackedRepeatedFields msg;
309 
310     for (int i = -100; i < 100; i++)
311       msg.add_field_int32(i);
312 
313     for (uint32_t i = 100; i < 200; i++)
314       msg.add_field_fixed32(i);
315 
316     for (int64_t i = 5000000000; i < 5000001000; i++)
317       msg.add_field_sfixed64(i);
318 
319     serialized = msg.SerializeAsString();
320   }
321   {
322     pbtest::PackedRepeatedFields msg;
323     EXPECT_TRUE(msg.ParseFromString(serialized));
324 
325     std::vector<int> exp_int32;
326     for (int i = -100; i < 100; i++)
327       exp_int32.emplace_back(i);
328     ASSERT_THAT(msg.field_int32(), ElementsAreArray(exp_int32));
329 
330     std::vector<uint32_t> exp_fixed32;
331     for (uint32_t i = 100; i < 200; i++)
332       exp_fixed32.emplace_back(i);
333     ASSERT_THAT(msg.field_fixed32(), ElementsAreArray(exp_fixed32));
334 
335     std::vector<int64_t> exp_sfixed64;
336     for (int64_t i = 5000000000; i < 5000001000; i++)
337       exp_sfixed64.emplace_back(i);
338     ASSERT_THAT(msg.field_sfixed64(), ElementsAreArray(exp_sfixed64));
339   }
340 }
341 }  // namespace
342 }  // namespace protozero
343