From 9307f4893008f7d6cf9473e906d4c896546c5c8c Mon Sep 17 00:00:00 2001 From: rsgowman Date: Tue, 5 Jun 2018 12:24:14 -0400 Subject: Skip unknown fields while decoding BatchGetDocumentsResponse proto objects (#1377) --- .../firebase/firestore/remote/serializer_test.cc | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'Firestore/core/test') diff --git a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc index 7dcdf6e..a902b5d 100644 --- a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc +++ b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc @@ -804,6 +804,68 @@ TEST_F(SerializerTest, EncodesNonEmptyDocument) { ExpectRoundTrip(key, fields, update_time, proto); } +TEST_F(SerializerTest, + BadBatchGetDocumentsResponseTagWithOtherValidTagsPresent) { + // A bad tag should be ignored, in which case, we should successfully + // deserialize the rest of the bytes as if it wasn't there. To craft these + // bytes, we'll use the same technique as + // EncodesFieldValuesWithRepeatedEntries (so go read the comments there + // first). + + // Copy of the real one (from the nanopb generated firestore.pb.h), but with + // only "missing" (a field from the original proto) and an extra_field. + struct google_firestore_v1beta1_BatchGetDocumentsResponse_Fake { + pb_callback_t missing; + int64_t extra_field; + }; + + // Copy of the real one (from the nanopb generated firestore.pb.c), but with + // only missing and an extra_field. Also modified such that extra_field + // now has a tag of 31. + const int invalid_tag = 31; + const pb_field_t + google_firestore_v1beta1_BatchGetDocumentsResponse_fields_Fake[2] = { + PB_FIELD(2, STRING, SINGULAR, CALLBACK, FIRST, + google_firestore_v1beta1_BatchGetDocumentsResponse_Fake, + missing, missing, 0), + PB_FIELD(invalid_tag, INT64, SINGULAR, STATIC, OTHER, + google_firestore_v1beta1_BatchGetDocumentsResponse_Fake, + extra_field, missing, 0), + }; + + const char* missing_value = "projects/p/databases/d/documents/one/two"; + google_firestore_v1beta1_BatchGetDocumentsResponse_Fake crafty_value; + crafty_value.missing.funcs.encode = + [](pb_ostream_t* stream, const pb_field_t* field, void* const* arg) { + const char* missing_value = static_cast(*arg); + if (!pb_encode_tag_for_field(stream, field)) return false; + return pb_encode_string(stream, + reinterpret_cast(missing_value), + strlen(missing_value)); + }; + crafty_value.missing.arg = const_cast(missing_value); + crafty_value.extra_field = 42; + + std::vector bytes(128); + pb_ostream_t stream = pb_ostream_from_buffer(bytes.data(), bytes.size()); + pb_encode(&stream, + google_firestore_v1beta1_BatchGetDocumentsResponse_fields_Fake, + &crafty_value); + bytes.resize(stream.bytes_written); + + // Decode the bytes into the model + StatusOr> actual_model_status = + serializer.DecodeMaybeDocument(bytes); + EXPECT_OK(actual_model_status); + std::unique_ptr actual_model = + std::move(actual_model_status).ValueOrDie(); + + // Ensure the decoded model is as expected. + NoDocument expected_model = + NoDocument(Key("one/two"), SnapshotVersion::None()); + EXPECT_EQ(expected_model, *actual_model.get()); +} + TEST_F(SerializerTest, DecodesNoDocument) { // We can't actually *encode* a NoDocument; the method exposed by the // serializer requires both the document key and contents (as an ObjectValue, -- cgit v1.2.3