Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 1 | // Protocol Buffers - Google's data interchange format |
| 2 | // Copyright 2008 Google Inc. All rights reserved. |
| 3 | // https://developers.google.com/protocol-buffers/ |
| 4 | // |
| 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
| 8 | // |
| 9 | // * Redistributions of source code must retain the above copyright |
| 10 | // notice, this list of conditions and the following disclaimer. |
| 11 | // * Redistributions in binary form must reproduce the above |
| 12 | // copyright notice, this list of conditions and the following disclaimer |
| 13 | // in the documentation and/or other materials provided with the |
| 14 | // distribution. |
| 15 | // * Neither the name of Google Inc. nor the names of its |
| 16 | // contributors may be used to endorse or promote products derived from |
| 17 | // this software without specific prior written permission. |
| 18 | // |
| 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | |
| 31 | #include <google/protobuf/util/internal/protostream_objectsource.h> |
| 32 | |
| 33 | #include <memory> |
| 34 | #ifndef _SHARED_PTR_H |
| 35 | #include <google/protobuf/stubs/shared_ptr.h> |
| 36 | #endif |
| 37 | #include <sstream> |
| 38 | |
| 39 | #include <google/protobuf/stubs/casts.h> |
| 40 | #include <google/protobuf/any.pb.h> |
| 41 | #include <google/protobuf/io/coded_stream.h> |
| 42 | #include <google/protobuf/io/zero_copy_stream_impl_lite.h> |
| 43 | #include <google/protobuf/descriptor.h> |
| 44 | #include <google/protobuf/util/internal/expecting_objectwriter.h> |
| 45 | #include <google/protobuf/util/internal/testdata/books.pb.h> |
| 46 | #include <google/protobuf/util/internal/testdata/field_mask.pb.h> |
| 47 | #include <google/protobuf/util/internal/type_info_test_helper.h> |
| 48 | #include <google/protobuf/util/internal/constants.h> |
| 49 | #include <google/protobuf/stubs/strutil.h> |
| 50 | #include <google/protobuf/util/internal/testdata/anys.pb.h> |
| 51 | #include <google/protobuf/util/internal/testdata/maps.pb.h> |
| 52 | #include <google/protobuf/util/internal/testdata/struct.pb.h> |
| 53 | #include <gtest/gtest.h> |
| 54 | |
| 55 | |
| 56 | namespace google { |
| 57 | namespace protobuf { |
| 58 | namespace util { |
| 59 | namespace converter { |
| 60 | |
| 61 | using google::protobuf::Descriptor; |
| 62 | using google::protobuf::DescriptorPool; |
| 63 | using google::protobuf::FileDescriptorProto; |
| 64 | using google::protobuf::Message; |
| 65 | using google::protobuf::io::ArrayInputStream; |
| 66 | using google::protobuf::io::CodedInputStream; |
| 67 | using util::Status; |
| 68 | using google::protobuf::testing::Author; |
| 69 | using google::protobuf::testing::BadAuthor; |
| 70 | using google::protobuf::testing::BadNestedBook; |
| 71 | using google::protobuf::testing::Book; |
| 72 | using google::protobuf::testing::Book_Label; |
| 73 | using google::protobuf::testing::NestedBook; |
| 74 | using google::protobuf::testing::PackedPrimitive; |
| 75 | using google::protobuf::testing::Primitive; |
| 76 | using google::protobuf::testing::more_author; |
| 77 | using google::protobuf::testing::maps::MapOut; |
| 78 | using google::protobuf::testing::anys::AnyOut; |
| 79 | using google::protobuf::testing::anys::AnyM; |
| 80 | using google::protobuf::testing::FieldMaskTest; |
| 81 | using google::protobuf::testing::NestedFieldMask; |
| 82 | using google::protobuf::testing::structs::StructType; |
| 83 | using ::testing::_; |
| 84 | |
| 85 | |
| 86 | namespace { |
| 87 | string GetTypeUrl(const Descriptor* descriptor) { |
| 88 | return string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(); |
| 89 | } |
| 90 | } // namespace |
| 91 | |
| 92 | class ProtostreamObjectSourceTest |
| 93 | : public ::testing::TestWithParam<testing::TypeInfoSource> { |
| 94 | protected: |
| 95 | ProtostreamObjectSourceTest() : helper_(GetParam()), mock_(), ow_(&mock_) { |
| 96 | helper_.ResetTypeInfo(Book::descriptor()); |
| 97 | } |
| 98 | |
| 99 | virtual ~ProtostreamObjectSourceTest() {} |
| 100 | |
| 101 | void DoTest(const Message& msg, const Descriptor* descriptor) { |
| 102 | Status status = ExecuteTest(msg, descriptor); |
| 103 | EXPECT_EQ(Status::OK, status); |
| 104 | } |
| 105 | |
| 106 | Status ExecuteTest(const Message& msg, const Descriptor* descriptor) { |
| 107 | ostringstream oss; |
| 108 | msg.SerializePartialToOstream(&oss); |
| 109 | string proto = oss.str(); |
| 110 | ArrayInputStream arr_stream(proto.data(), proto.size()); |
| 111 | CodedInputStream in_stream(&arr_stream); |
| 112 | |
| 113 | google::protobuf::scoped_ptr<ProtoStreamObjectSource> os( |
| 114 | helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor))); |
| 115 | return os->WriteTo(&mock_); |
| 116 | } |
| 117 | |
| 118 | void PrepareExpectingObjectWriterForRepeatedPrimitive() { |
| 119 | ow_.StartObject("") |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 120 | ->StartList("repFix32") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 121 | ->RenderUint32("", bit_cast<uint32>(3201)) |
| 122 | ->RenderUint32("", bit_cast<uint32>(0)) |
| 123 | ->RenderUint32("", bit_cast<uint32>(3202)) |
| 124 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 125 | ->StartList("repU32") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 126 | ->RenderUint32("", bit_cast<uint32>(3203)) |
| 127 | ->RenderUint32("", bit_cast<uint32>(0)) |
| 128 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 129 | ->StartList("repI32") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 130 | ->RenderInt32("", 0) |
| 131 | ->RenderInt32("", 3204) |
| 132 | ->RenderInt32("", 3205) |
| 133 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 134 | ->StartList("repSf32") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 135 | ->RenderInt32("", 3206) |
| 136 | ->RenderInt32("", 0) |
| 137 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 138 | ->StartList("repS32") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 139 | ->RenderInt32("", 0) |
| 140 | ->RenderInt32("", 3207) |
| 141 | ->RenderInt32("", 3208) |
| 142 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 143 | ->StartList("repFix64") |
Feng Xiao | 818c5ee | 2015-06-15 21:42:57 -0700 | [diff] [blame] | 144 | ->RenderUint64("", bit_cast<uint64>(6401LL)) |
| 145 | ->RenderUint64("", bit_cast<uint64>(0LL)) |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 146 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 147 | ->StartList("repU64") |
Feng Xiao | 818c5ee | 2015-06-15 21:42:57 -0700 | [diff] [blame] | 148 | ->RenderUint64("", bit_cast<uint64>(0LL)) |
| 149 | ->RenderUint64("", bit_cast<uint64>(6402LL)) |
| 150 | ->RenderUint64("", bit_cast<uint64>(6403LL)) |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 151 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 152 | ->StartList("repI64") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 153 | ->RenderInt64("", 6404L) |
| 154 | ->RenderInt64("", 0L) |
| 155 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 156 | ->StartList("repSf64") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 157 | ->RenderInt64("", 0L) |
| 158 | ->RenderInt64("", 6405L) |
| 159 | ->RenderInt64("", 6406L) |
| 160 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 161 | ->StartList("repS64") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 162 | ->RenderInt64("", 6407L) |
| 163 | ->RenderInt64("", 0L) |
| 164 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 165 | ->StartList("repFloat") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 166 | ->RenderFloat("", 0.0f) |
| 167 | ->RenderFloat("", 32.1f) |
| 168 | ->RenderFloat("", 32.2f) |
| 169 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 170 | ->StartList("repDouble") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 171 | ->RenderDouble("", 64.1L) |
| 172 | ->RenderDouble("", 0.0L) |
| 173 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 174 | ->StartList("repBool") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 175 | ->RenderBool("", true) |
| 176 | ->RenderBool("", false) |
| 177 | ->EndList() |
| 178 | ->EndObject(); |
| 179 | } |
| 180 | |
| 181 | Primitive PrepareRepeatedPrimitive() { |
| 182 | Primitive primitive; |
| 183 | primitive.add_rep_fix32(3201); |
| 184 | primitive.add_rep_fix32(0); |
| 185 | primitive.add_rep_fix32(3202); |
| 186 | primitive.add_rep_u32(3203); |
| 187 | primitive.add_rep_u32(0); |
| 188 | primitive.add_rep_i32(0); |
| 189 | primitive.add_rep_i32(3204); |
| 190 | primitive.add_rep_i32(3205); |
| 191 | primitive.add_rep_sf32(3206); |
| 192 | primitive.add_rep_sf32(0); |
| 193 | primitive.add_rep_s32(0); |
| 194 | primitive.add_rep_s32(3207); |
| 195 | primitive.add_rep_s32(3208); |
| 196 | primitive.add_rep_fix64(6401L); |
| 197 | primitive.add_rep_fix64(0L); |
| 198 | primitive.add_rep_u64(0L); |
| 199 | primitive.add_rep_u64(6402L); |
| 200 | primitive.add_rep_u64(6403L); |
| 201 | primitive.add_rep_i64(6404L); |
| 202 | primitive.add_rep_i64(0L); |
| 203 | primitive.add_rep_sf64(0L); |
| 204 | primitive.add_rep_sf64(6405L); |
| 205 | primitive.add_rep_sf64(6406L); |
| 206 | primitive.add_rep_s64(6407L); |
| 207 | primitive.add_rep_s64(0L); |
| 208 | primitive.add_rep_float(0.0f); |
| 209 | primitive.add_rep_float(32.1f); |
| 210 | primitive.add_rep_float(32.2f); |
| 211 | primitive.add_rep_double(64.1L); |
| 212 | primitive.add_rep_double(0.0); |
| 213 | primitive.add_rep_bool(true); |
| 214 | primitive.add_rep_bool(false); |
| 215 | |
| 216 | PrepareExpectingObjectWriterForRepeatedPrimitive(); |
| 217 | return primitive; |
| 218 | } |
| 219 | |
| 220 | PackedPrimitive PreparePackedPrimitive() { |
| 221 | PackedPrimitive primitive; |
| 222 | primitive.add_rep_fix32(3201); |
| 223 | primitive.add_rep_fix32(0); |
| 224 | primitive.add_rep_fix32(3202); |
| 225 | primitive.add_rep_u32(3203); |
| 226 | primitive.add_rep_u32(0); |
| 227 | primitive.add_rep_i32(0); |
| 228 | primitive.add_rep_i32(3204); |
| 229 | primitive.add_rep_i32(3205); |
| 230 | primitive.add_rep_sf32(3206); |
| 231 | primitive.add_rep_sf32(0); |
| 232 | primitive.add_rep_s32(0); |
| 233 | primitive.add_rep_s32(3207); |
| 234 | primitive.add_rep_s32(3208); |
| 235 | primitive.add_rep_fix64(6401L); |
| 236 | primitive.add_rep_fix64(0L); |
| 237 | primitive.add_rep_u64(0L); |
| 238 | primitive.add_rep_u64(6402L); |
| 239 | primitive.add_rep_u64(6403L); |
| 240 | primitive.add_rep_i64(6404L); |
| 241 | primitive.add_rep_i64(0L); |
| 242 | primitive.add_rep_sf64(0L); |
| 243 | primitive.add_rep_sf64(6405L); |
| 244 | primitive.add_rep_sf64(6406L); |
| 245 | primitive.add_rep_s64(6407L); |
| 246 | primitive.add_rep_s64(0L); |
| 247 | primitive.add_rep_float(0.0f); |
| 248 | primitive.add_rep_float(32.1f); |
| 249 | primitive.add_rep_float(32.2f); |
| 250 | primitive.add_rep_double(64.1L); |
| 251 | primitive.add_rep_double(0.0); |
| 252 | primitive.add_rep_bool(true); |
| 253 | primitive.add_rep_bool(false); |
| 254 | |
| 255 | PrepareExpectingObjectWriterForRepeatedPrimitive(); |
| 256 | return primitive; |
| 257 | } |
| 258 | |
| 259 | testing::TypeInfoTestHelper helper_; |
| 260 | |
| 261 | ::testing::NiceMock<MockObjectWriter> mock_; |
| 262 | ExpectingObjectWriter ow_; |
| 263 | }; |
| 264 | |
| 265 | INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, |
| 266 | ProtostreamObjectSourceTest, |
| 267 | ::testing::Values( |
| 268 | testing::USE_TYPE_RESOLVER)); |
| 269 | |
| 270 | TEST_P(ProtostreamObjectSourceTest, EmptyMessage) { |
| 271 | Book empty; |
| 272 | ow_.StartObject("")->EndObject(); |
| 273 | DoTest(empty, Book::descriptor()); |
| 274 | } |
| 275 | |
| 276 | TEST_P(ProtostreamObjectSourceTest, Primitives) { |
| 277 | Primitive primitive; |
| 278 | primitive.set_fix32(3201); |
| 279 | primitive.set_u32(3202); |
| 280 | primitive.set_i32(3203); |
| 281 | primitive.set_sf32(3204); |
| 282 | primitive.set_s32(3205); |
| 283 | primitive.set_fix64(6401L); |
| 284 | primitive.set_u64(6402L); |
| 285 | primitive.set_i64(6403L); |
| 286 | primitive.set_sf64(6404L); |
| 287 | primitive.set_s64(6405L); |
| 288 | primitive.set_str("String Value"); |
| 289 | primitive.set_bytes("Some Bytes"); |
| 290 | primitive.set_float_(32.1f); |
| 291 | primitive.set_double_(64.1L); |
| 292 | primitive.set_bool_(true); |
| 293 | |
| 294 | ow_.StartObject("") |
| 295 | ->RenderUint32("fix32", bit_cast<uint32>(3201)) |
| 296 | ->RenderUint32("u32", bit_cast<uint32>(3202)) |
| 297 | ->RenderInt32("i32", 3203) |
| 298 | ->RenderInt32("sf32", 3204) |
| 299 | ->RenderInt32("s32", 3205) |
Feng Xiao | 818c5ee | 2015-06-15 21:42:57 -0700 | [diff] [blame] | 300 | ->RenderUint64("fix64", bit_cast<uint64>(6401LL)) |
| 301 | ->RenderUint64("u64", bit_cast<uint64>(6402LL)) |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 302 | ->RenderInt64("i64", 6403L) |
| 303 | ->RenderInt64("sf64", 6404L) |
| 304 | ->RenderInt64("s64", 6405L) |
| 305 | ->RenderString("str", "String Value") |
| 306 | ->RenderBytes("bytes", "Some Bytes") |
| 307 | ->RenderFloat("float", 32.1f) |
| 308 | ->RenderDouble("double", 64.1L) |
| 309 | ->RenderBool("bool", true) |
| 310 | ->EndObject(); |
| 311 | DoTest(primitive, Primitive::descriptor()); |
| 312 | } |
| 313 | |
| 314 | TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) { |
| 315 | Primitive primitive = PrepareRepeatedPrimitive(); |
| 316 | primitive.add_rep_str("String One"); |
| 317 | primitive.add_rep_str("String Two"); |
| 318 | primitive.add_rep_bytes("Some Bytes"); |
| 319 | |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 320 | ow_.StartList("repStr") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 321 | ->RenderString("", "String One") |
| 322 | ->RenderString("", "String Two") |
| 323 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 324 | ->StartList("repBytes") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 325 | ->RenderBytes("", "Some Bytes") |
| 326 | ->EndList(); |
| 327 | DoTest(primitive, Primitive::descriptor()); |
| 328 | } |
| 329 | |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 330 | TEST_P(ProtostreamObjectSourceTest, CustomJsonName) { |
| 331 | Author author; |
| 332 | author.set_id(12345); |
| 333 | |
| 334 | ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject(); |
| 335 | DoTest(author, Author::descriptor()); |
| 336 | } |
| 337 | |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 338 | TEST_P(ProtostreamObjectSourceTest, NestedMessage) { |
| 339 | Author* author = new Author(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 340 | author->set_name("Tolstoy"); |
| 341 | Book book; |
| 342 | book.set_title("My Book"); |
| 343 | book.set_allocated_author(author); |
| 344 | |
| 345 | ow_.StartObject("") |
| 346 | ->RenderString("title", "My Book") |
| 347 | ->StartObject("author") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 348 | ->RenderString("name", "Tolstoy") |
| 349 | ->EndObject() |
| 350 | ->EndObject(); |
| 351 | DoTest(book, Book::descriptor()); |
| 352 | } |
| 353 | |
| 354 | TEST_P(ProtostreamObjectSourceTest, RepeatingField) { |
| 355 | Author author; |
| 356 | author.set_alive(false); |
| 357 | author.set_name("john"); |
| 358 | author.add_pseudonym("phil"); |
| 359 | author.add_pseudonym("bob"); |
| 360 | |
| 361 | ow_.StartObject("") |
| 362 | ->RenderBool("alive", false) |
| 363 | ->RenderString("name", "john") |
| 364 | ->StartList("pseudonym") |
| 365 | ->RenderString("", "phil") |
| 366 | ->RenderString("", "bob") |
| 367 | ->EndList() |
| 368 | ->EndObject(); |
| 369 | DoTest(author, Author::descriptor()); |
| 370 | } |
| 371 | |
| 372 | TEST_P(ProtostreamObjectSourceTest, PackedRepeatingFields) { |
| 373 | DoTest(PreparePackedPrimitive(), PackedPrimitive::descriptor()); |
| 374 | } |
| 375 | |
| 376 | TEST_P(ProtostreamObjectSourceTest, NonPackedPackableFieldsActuallyPacked) { |
| 377 | // Protostream is packed, but parse with non-packed Primitive. |
| 378 | DoTest(PreparePackedPrimitive(), Primitive::descriptor()); |
| 379 | } |
| 380 | |
| 381 | TEST_P(ProtostreamObjectSourceTest, PackedPackableFieldNotActuallyPacked) { |
| 382 | // Protostream is not packed, but parse with PackedPrimitive. |
| 383 | DoTest(PrepareRepeatedPrimitive(), PackedPrimitive::descriptor()); |
| 384 | } |
| 385 | |
| 386 | TEST_P(ProtostreamObjectSourceTest, BadAuthor) { |
| 387 | Author author; |
| 388 | author.set_alive(false); |
| 389 | author.set_name("john"); |
| 390 | author.set_id(1234L); |
| 391 | author.add_pseudonym("phil"); |
| 392 | author.add_pseudonym("bob"); |
| 393 | |
| 394 | ow_.StartObject("") |
| 395 | ->StartList("alive") |
| 396 | ->RenderBool("", false) |
| 397 | ->EndList() |
| 398 | ->StartList("name") |
| 399 | ->RenderUint64("", static_cast<uint64>('j')) |
| 400 | ->RenderUint64("", static_cast<uint64>('o')) |
| 401 | ->RenderUint64("", static_cast<uint64>('h')) |
| 402 | ->RenderUint64("", static_cast<uint64>('n')) |
| 403 | ->EndList() |
| 404 | ->RenderString("pseudonym", "phil") |
| 405 | ->RenderString("pseudonym", "bob") |
| 406 | ->EndObject(); |
| 407 | // Protostream created with Author, but parsed with BadAuthor. |
| 408 | DoTest(author, BadAuthor::descriptor()); |
| 409 | } |
| 410 | |
| 411 | TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) { |
| 412 | Book* book = new Book(); |
| 413 | book->set_length(250); |
| 414 | book->set_published(2014L); |
| 415 | NestedBook nested; |
| 416 | nested.set_allocated_book(book); |
| 417 | |
| 418 | ow_.StartObject("") |
| 419 | ->StartList("book") |
| 420 | ->RenderUint32("", 24) // tag for field length (3 << 3) |
| 421 | ->RenderUint32("", 250) |
| 422 | ->RenderUint32("", 32) // tag for field published (4 << 3) |
| 423 | ->RenderUint32("", 2014) |
| 424 | ->EndList() |
| 425 | ->EndObject(); |
| 426 | // Protostream created with NestedBook, but parsed with BadNestedBook. |
| 427 | DoTest(nested, BadNestedBook::descriptor()); |
| 428 | } |
| 429 | |
| 430 | TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) { |
| 431 | BadNestedBook nested; |
| 432 | nested.add_book(1); |
| 433 | nested.add_book(2); |
| 434 | nested.add_book(3); |
| 435 | nested.add_book(4); |
| 436 | nested.add_book(5); |
| 437 | nested.add_book(6); |
| 438 | nested.add_book(7); |
| 439 | |
| 440 | ow_.StartObject("")->StartObject("book")->EndObject()->EndObject(); |
| 441 | // Protostream created with BadNestedBook, but parsed with NestedBook. |
| 442 | DoTest(nested, NestedBook::descriptor()); |
| 443 | } |
| 444 | |
| 445 | TEST_P(ProtostreamObjectSourceTest, |
| 446 | LongRepeatedListDoesNotBreakIntoMultipleJsonLists) { |
| 447 | Book book; |
| 448 | |
| 449 | int repeat = 10000; |
| 450 | for (int i = 0; i < repeat; ++i) { |
| 451 | Book_Label* label = book.add_labels(); |
| 452 | label->set_key(StrCat("i", i)); |
| 453 | label->set_value(StrCat("v", i)); |
| 454 | } |
| 455 | |
| 456 | // Make sure StartList and EndList are called exactly once (see b/18227499 for |
| 457 | // problems when this doesn't happen) |
| 458 | EXPECT_CALL(mock_, StartList(_)).Times(1); |
| 459 | EXPECT_CALL(mock_, EndList()).Times(1); |
| 460 | |
| 461 | DoTest(book, Book::descriptor()); |
| 462 | } |
| 463 | |
| 464 | class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest { |
| 465 | protected: |
| 466 | ProtostreamObjectSourceMapsTest() { |
| 467 | helper_.ResetTypeInfo(MapOut::descriptor()); |
| 468 | } |
| 469 | }; |
| 470 | |
| 471 | INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, |
| 472 | ProtostreamObjectSourceMapsTest, |
| 473 | ::testing::Values( |
| 474 | testing::USE_TYPE_RESOLVER)); |
| 475 | |
| 476 | // Tests JSON map. |
| 477 | // |
| 478 | // This is the example expected output. |
| 479 | // { |
| 480 | // "map1": { |
| 481 | // "key1": { |
| 482 | // "foo": "foovalue" |
| 483 | // }, |
| 484 | // "key2": { |
| 485 | // "foo": "barvalue" |
| 486 | // } |
| 487 | // }, |
| 488 | // "map2": { |
| 489 | // "nestedself": { |
| 490 | // "map1": { |
| 491 | // "nested_key1": { |
| 492 | // "foo": "nested_foo" |
| 493 | // } |
| 494 | // }, |
| 495 | // "bar": "nested_bar_string" |
| 496 | // } |
| 497 | // }, |
| 498 | // "map3": { |
| 499 | // "111": "one one one" |
| 500 | // }, |
| 501 | // "bar": "top bar" |
| 502 | // } |
| 503 | TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) { |
| 504 | MapOut out; |
| 505 | (*out.mutable_map1())["key1"].set_foo("foovalue"); |
| 506 | (*out.mutable_map1())["key2"].set_foo("barvalue"); |
| 507 | |
| 508 | MapOut* nested_value = &(*out.mutable_map2())["nestedself"]; |
| 509 | (*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo"); |
| 510 | nested_value->set_bar("nested_bar_string"); |
| 511 | |
| 512 | (*out.mutable_map3())[111] = "one one one"; |
| 513 | |
| 514 | out.set_bar("top bar"); |
| 515 | |
| 516 | ow_.StartObject("") |
| 517 | ->StartObject("map1") |
| 518 | ->StartObject("key1") |
| 519 | ->RenderString("foo", "foovalue") |
| 520 | ->EndObject() |
| 521 | ->StartObject("key2") |
| 522 | ->RenderString("foo", "barvalue") |
| 523 | ->EndObject() |
| 524 | ->StartObject("map2") |
| 525 | ->StartObject("nestedself") |
| 526 | ->StartObject("map1") |
| 527 | ->StartObject("nested_key1") |
| 528 | ->RenderString("foo", "nested_foo") |
| 529 | ->EndObject() |
| 530 | ->EndObject() |
| 531 | ->RenderString("bar", "nested_bar_string") |
| 532 | ->EndObject() |
| 533 | ->EndObject() |
| 534 | ->StartObject("map3") |
| 535 | ->RenderString("111", "one one one") |
| 536 | ->EndObject() |
| 537 | ->EndObject() |
| 538 | ->RenderString("bar", "top bar") |
| 539 | ->EndObject(); |
| 540 | |
| 541 | DoTest(out, MapOut::descriptor()); |
| 542 | } |
| 543 | |
| 544 | class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest { |
| 545 | protected: |
| 546 | ProtostreamObjectSourceAnysTest() { |
| 547 | helper_.ResetTypeInfo(AnyOut::descriptor(), |
| 548 | google::protobuf::Any::descriptor()); |
| 549 | } |
| 550 | }; |
| 551 | |
| 552 | INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, |
| 553 | ProtostreamObjectSourceAnysTest, |
| 554 | ::testing::Values( |
| 555 | testing::USE_TYPE_RESOLVER)); |
| 556 | |
| 557 | // Tests JSON any support. |
| 558 | // |
| 559 | // This is the example expected output. |
| 560 | // { |
| 561 | // "any": { |
| 562 | // "@type": "type.googleapis.com/google.protobuf.testing.anys.AnyM" |
| 563 | // "foo": "foovalue" |
| 564 | // } |
| 565 | // } |
| 566 | TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) { |
| 567 | AnyOut out; |
| 568 | ::google::protobuf::Any* any = out.mutable_any(); |
| 569 | |
| 570 | AnyM m; |
| 571 | m.set_foo("foovalue"); |
| 572 | any->PackFrom(m); |
| 573 | |
| 574 | ow_.StartObject("") |
| 575 | ->StartObject("any") |
| 576 | ->RenderString("@type", |
| 577 | "type.googleapis.com/google.protobuf.testing.anys.AnyM") |
| 578 | ->RenderString("foo", "foovalue") |
| 579 | ->EndObject() |
| 580 | ->EndObject(); |
| 581 | |
| 582 | DoTest(out, AnyOut::descriptor()); |
| 583 | } |
| 584 | |
| 585 | TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) { |
| 586 | AnyOut out; |
| 587 | ::google::protobuf::Any* any = out.mutable_any(); |
| 588 | any->set_type_url("type.googleapis.com/google.protobuf.Any"); |
| 589 | |
| 590 | ::google::protobuf::Any nested_any; |
| 591 | nested_any.set_type_url( |
| 592 | "type.googleapis.com/google.protobuf.testing.anys.AnyM"); |
| 593 | |
| 594 | AnyM m; |
| 595 | m.set_foo("foovalue"); |
| 596 | nested_any.set_value(m.SerializeAsString()); |
| 597 | |
| 598 | any->set_value(nested_any.SerializeAsString()); |
| 599 | |
| 600 | ow_.StartObject("") |
| 601 | ->StartObject("any") |
| 602 | ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") |
| 603 | ->StartObject("value") |
| 604 | ->RenderString("@type", |
| 605 | "type.googleapis.com/google.protobuf.testing.anys.AnyM") |
| 606 | ->RenderString("foo", "foovalue") |
| 607 | ->EndObject() |
| 608 | ->EndObject() |
| 609 | ->EndObject(); |
| 610 | |
| 611 | DoTest(out, AnyOut::descriptor()); |
| 612 | } |
| 613 | |
| 614 | TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) { |
| 615 | AnyOut out; |
| 616 | ::google::protobuf::Any* any = out.mutable_any(); |
| 617 | any->set_type_url("type.googleapis.com/google.protobuf.Any"); |
| 618 | |
| 619 | ::google::protobuf::Any nested_any; |
| 620 | nested_any.set_type_url("type.googleapis.com/google.protobuf.Any"); |
| 621 | |
| 622 | ::google::protobuf::Any second_nested_any; |
| 623 | second_nested_any.set_type_url( |
| 624 | "type.googleapis.com/google.protobuf.testing.anys.AnyM"); |
| 625 | |
| 626 | AnyM m; |
| 627 | m.set_foo("foovalue"); |
| 628 | second_nested_any.set_value(m.SerializeAsString()); |
| 629 | nested_any.set_value(second_nested_any.SerializeAsString()); |
| 630 | any->set_value(nested_any.SerializeAsString()); |
| 631 | |
| 632 | ow_.StartObject("") |
| 633 | ->StartObject("any") |
| 634 | ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") |
| 635 | ->StartObject("value") |
| 636 | ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") |
| 637 | ->StartObject("value") |
| 638 | ->RenderString("@type", |
| 639 | "type.googleapis.com/google.protobuf.testing.anys.AnyM") |
| 640 | ->RenderString("foo", "foovalue") |
| 641 | ->EndObject() |
| 642 | ->EndObject() |
| 643 | ->EndObject() |
| 644 | ->EndObject(); |
| 645 | |
| 646 | DoTest(out, AnyOut::descriptor()); |
| 647 | } |
| 648 | |
| 649 | TEST_P(ProtostreamObjectSourceAnysTest, EmptyAnyOutputsEmptyObject) { |
| 650 | AnyOut out; |
| 651 | out.mutable_any(); |
| 652 | |
| 653 | ow_.StartObject("")->StartObject("any")->EndObject()->EndObject(); |
| 654 | |
| 655 | DoTest(out, AnyOut::descriptor()); |
| 656 | } |
| 657 | |
| 658 | TEST_P(ProtostreamObjectSourceAnysTest, EmptyWithTypeAndNoValueOutputsType) { |
| 659 | AnyOut out; |
| 660 | out.mutable_any()->set_type_url("foo.googleapis.com/my.Type"); |
| 661 | |
| 662 | ow_.StartObject("") |
| 663 | ->StartObject("any") |
| 664 | ->RenderString("@type", "foo.googleapis.com/my.Type") |
| 665 | ->EndObject() |
| 666 | ->EndObject(); |
| 667 | |
| 668 | DoTest(out, AnyOut::descriptor()); |
| 669 | } |
| 670 | |
| 671 | TEST_P(ProtostreamObjectSourceAnysTest, MissingTypeUrlError) { |
| 672 | AnyOut out; |
| 673 | ::google::protobuf::Any* any = out.mutable_any(); |
| 674 | |
| 675 | AnyM m; |
| 676 | m.set_foo("foovalue"); |
| 677 | any->set_value(m.SerializeAsString()); |
| 678 | |
| 679 | // We start the "AnyOut" part and then fail when we hit the Any object. |
| 680 | ow_.StartObject(""); |
| 681 | |
| 682 | Status status = ExecuteTest(out, AnyOut::descriptor()); |
| 683 | EXPECT_EQ(util::error::INTERNAL, status.error_code()); |
| 684 | } |
| 685 | |
| 686 | TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeServiceError) { |
| 687 | AnyOut out; |
| 688 | ::google::protobuf::Any* any = out.mutable_any(); |
| 689 | any->set_type_url("foo.googleapis.com/my.own.Type"); |
| 690 | |
| 691 | AnyM m; |
| 692 | m.set_foo("foovalue"); |
| 693 | any->set_value(m.SerializeAsString()); |
| 694 | |
| 695 | // We start the "AnyOut" part and then fail when we hit the Any object. |
| 696 | ow_.StartObject(""); |
| 697 | |
| 698 | Status status = ExecuteTest(out, AnyOut::descriptor()); |
| 699 | EXPECT_EQ(util::error::INTERNAL, status.error_code()); |
| 700 | } |
| 701 | |
| 702 | TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeError) { |
| 703 | AnyOut out; |
| 704 | ::google::protobuf::Any* any = out.mutable_any(); |
| 705 | any->set_type_url("type.googleapis.com/unknown.Type"); |
| 706 | |
| 707 | AnyM m; |
| 708 | m.set_foo("foovalue"); |
| 709 | any->set_value(m.SerializeAsString()); |
| 710 | |
| 711 | // We start the "AnyOut" part and then fail when we hit the Any object. |
| 712 | ow_.StartObject(""); |
| 713 | |
| 714 | Status status = ExecuteTest(out, AnyOut::descriptor()); |
| 715 | EXPECT_EQ(util::error::INTERNAL, status.error_code()); |
| 716 | } |
| 717 | |
| 718 | class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest { |
| 719 | protected: |
| 720 | ProtostreamObjectSourceStructTest() { |
| 721 | helper_.ResetTypeInfo(StructType::descriptor(), |
| 722 | google::protobuf::Struct::descriptor()); |
| 723 | } |
| 724 | }; |
| 725 | |
| 726 | INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, |
| 727 | ProtostreamObjectSourceStructTest, |
| 728 | ::testing::Values( |
| 729 | testing::USE_TYPE_RESOLVER)); |
| 730 | |
| 731 | // Tests struct |
| 732 | // |
| 733 | // "object": { |
| 734 | // "k1": 123, |
| 735 | // "k2": true |
| 736 | // } |
| 737 | TEST_P(ProtostreamObjectSourceStructTest, StructRenderSuccess) { |
| 738 | StructType out; |
| 739 | google::protobuf::Struct* s = out.mutable_object(); |
| 740 | s->mutable_fields()->operator[]("k1").set_number_value(123); |
| 741 | s->mutable_fields()->operator[]("k2").set_bool_value(true); |
| 742 | |
| 743 | ow_.StartObject("") |
| 744 | ->StartObject("object") |
| 745 | ->RenderDouble("k1", 123) |
| 746 | ->RenderBool("k2", true) |
| 747 | ->EndObject() |
| 748 | ->EndObject(); |
| 749 | |
| 750 | DoTest(out, StructType::descriptor()); |
| 751 | } |
| 752 | |
| 753 | TEST_P(ProtostreamObjectSourceStructTest, MissingValueSkipsField) { |
| 754 | StructType out; |
| 755 | google::protobuf::Struct* s = out.mutable_object(); |
| 756 | s->mutable_fields()->operator[]("k1"); |
| 757 | |
| 758 | ow_.StartObject("")->StartObject("object")->EndObject()->EndObject(); |
| 759 | |
| 760 | DoTest(out, StructType::descriptor()); |
| 761 | } |
| 762 | |
| 763 | class ProtostreamObjectSourceFieldMaskTest |
| 764 | : public ProtostreamObjectSourceTest { |
| 765 | protected: |
| 766 | ProtostreamObjectSourceFieldMaskTest() { |
| 767 | helper_.ResetTypeInfo(FieldMaskTest::descriptor(), |
| 768 | google::protobuf::FieldMask::descriptor()); |
| 769 | } |
| 770 | }; |
| 771 | |
| 772 | INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, |
| 773 | ProtostreamObjectSourceFieldMaskTest, |
| 774 | ::testing::Values( |
| 775 | testing::USE_TYPE_RESOLVER)); |
| 776 | |
| 777 | TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { |
| 778 | FieldMaskTest out; |
| 779 | out.set_id("1"); |
| 780 | out.mutable_single_mask()->add_paths("path1"); |
| 781 | out.mutable_single_mask()->add_paths("snake_case_path2"); |
| 782 | ::google::protobuf::FieldMask* mask = out.add_repeated_mask(); |
| 783 | mask->add_paths("path3"); |
| 784 | mask = out.add_repeated_mask(); |
| 785 | mask->add_paths("snake_case_path4"); |
| 786 | mask->add_paths("path5"); |
| 787 | NestedFieldMask* nested = out.add_nested_mask(); |
| 788 | nested->set_data("data"); |
| 789 | nested->mutable_single_mask()->add_paths("nested.path1"); |
| 790 | nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2"); |
| 791 | mask = nested->add_repeated_mask(); |
| 792 | mask->add_paths("nested_field.path3"); |
| 793 | mask->add_paths("nested.snake_case_path4"); |
| 794 | mask = nested->add_repeated_mask(); |
| 795 | mask->add_paths("nested.path5"); |
| 796 | mask = nested->add_repeated_mask(); |
| 797 | mask->add_paths( |
| 798 | "snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case." |
| 799 | "map_field[\"map_key_sho\\\"uld_be_ignored\"]"); |
| 800 | |
| 801 | ow_.StartObject("") |
| 802 | ->RenderString("id", "1") |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 803 | ->RenderString("singleMask", "path1,snakeCasePath2") |
| 804 | ->StartList("repeatedMask") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 805 | ->RenderString("", "path3") |
| 806 | ->RenderString("", "snakeCasePath4,path5") |
| 807 | ->EndList() |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 808 | ->StartList("nestedMask") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 809 | ->StartObject("") |
| 810 | ->RenderString("data", "data") |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 811 | ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2") |
| 812 | ->StartList("repeatedMask") |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 813 | ->RenderString("", "nestedField.path3,nested.snakeCasePath4") |
| 814 | ->RenderString("", "nested.path5") |
| 815 | ->RenderString("", |
| 816 | "snakeCase.mapField[\"map_key_should_be_ignored\"]." |
| 817 | "nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_" |
| 818 | "ignored\"]") |
| 819 | ->EndList() |
| 820 | ->EndObject() |
| 821 | ->EndList() |
| 822 | ->EndObject(); |
| 823 | |
| 824 | DoTest(out, FieldMaskTest::descriptor()); |
| 825 | } |
| 826 | |
| 827 | } // namespace converter |
| 828 | } // namespace util |
| 829 | } // namespace protobuf |
| 830 | } // namespace google |