|
|
@@ -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<const char*>(*arg);
|
|
|
+ if (!pb_encode_tag_for_field(stream, field)) return false;
|
|
|
+ return pb_encode_string(stream,
|
|
|
+ reinterpret_cast<const uint8_t*>(missing_value),
|
|
|
+ strlen(missing_value));
|
|
|
+ };
|
|
|
+ crafty_value.missing.arg = const_cast<char*>(missing_value);
|
|
|
+ crafty_value.extra_field = 42;
|
|
|
+
|
|
|
+ std::vector<uint8_t> 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<std::unique_ptr<MaybeDocument>> actual_model_status =
|
|
|
+ serializer.DecodeMaybeDocument(bytes);
|
|
|
+ EXPECT_OK(actual_model_status);
|
|
|
+ std::unique_ptr<MaybeDocument> 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,
|