From 26b8ac9ee43bb67b08e4bc62af98ac6bda2f121c Mon Sep 17 00:00:00 2001 From: rsgowman Date: Mon, 4 Jun 2018 15:31:10 -0400 Subject: Skip unknown fields while decoding FieldValue proto objects. (#1354) --- .../firebase/firestore/remote/serializer_test.cc | 65 ++++++++++++++++++---- 1 file changed, 55 insertions(+), 10 deletions(-) (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 96ffa9e..7dcdf6e 100644 --- a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc +++ b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc @@ -605,7 +605,12 @@ TEST_F(SerializerTest, BadTimestampValue_TooSmall) { Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } -TEST_F(SerializerTest, BadTag) { +TEST_F(SerializerTest, BadFieldValueTagAndNoOtherTagPresent) { + // A bad tag should be ignored. But if there are *no* valid tags, then we + // don't know the type of the FieldValue. Although it might be reasonable to + // assume some sort of default type in this situation, we've decided to fail + // the deserialization process in this case instead. + std::vector bytes = EncodeFieldValue(&serializer, FieldValue::NullValue()); @@ -615,15 +620,55 @@ TEST_F(SerializerTest, BadTag) { // Specifically 31. 0xf8 represents field number 31 encoded as a varint. Mutate(&bytes[0], /*expected_initial_value=*/0x58, /*new_value=*/0xf8); - // TODO(rsgowman): The behaviour is *temporarily* slightly different during - // development; this will cause a failed assertion rather than a failed - // status. Remove this EXPECT_ANY_THROW statement (and reenable the - // following commented out statement) once the corresponding assert has been - // removed from serializer.cc. - EXPECT_ANY_THROW(ExpectFailedStatusDuringFieldValueDecode( - Status(FirestoreErrorCode::DataLoss, "ignored"), bytes)); - // ExpectFailedStatusDuringFieldValueDecode( - // Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); + ExpectFailedStatusDuringFieldValueDecode( + Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); +} + +TEST_F(SerializerTest, BadFieldValueTagWithOtherValidTagsPresent) { + // 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 document.pb.h), but with + // only boolean_value and integer_value. + struct google_firestore_v1beta1_Value_Fake { + bool boolean_value; + int64_t integer_value; + }; + + // Copy of the real one (from the nanopb generated document.pb.c), but with + // only boolean_value and integer_value. Also modified such that integer_value + // now has an invalid tag (instead of 2). + const int invalid_tag = 31; + const pb_field_t google_firestore_v1beta1_Value_fields_Fake[2] = { + PB_FIELD(1, BOOL, SINGULAR, STATIC, FIRST, + google_firestore_v1beta1_Value_Fake, boolean_value, + boolean_value, 0), + PB_FIELD(invalid_tag, INT64, SINGULAR, STATIC, OTHER, + google_firestore_v1beta1_Value_Fake, integer_value, + boolean_value, 0), + }; + + // Craft the bytes. boolean_value has a smaller tag, so it'll get encoded + // first, normally implying integer_value should "win". Except that + // integer_value isn't a valid tag, so it should be ignored here. + google_firestore_v1beta1_Value_Fake crafty_value{false, int64_t{42}}; + std::vector bytes(128); + pb_ostream_t stream = pb_ostream_from_buffer(bytes.data(), bytes.size()); + pb_encode(&stream, google_firestore_v1beta1_Value_fields_Fake, &crafty_value); + bytes.resize(stream.bytes_written); + + // Decode the bytes into the model + StatusOr actual_model_status = serializer.DecodeFieldValue(bytes); + EXPECT_OK(actual_model_status); + FieldValue actual_model = actual_model_status.ValueOrDie(); + + // Ensure the decoded model is as expected. + FieldValue expected_model = FieldValue::BooleanValue(false); + EXPECT_EQ(FieldValue::Type::Boolean, actual_model.type()); + EXPECT_EQ(expected_model, actual_model); } TEST_F(SerializerTest, TagVarintWiretypeStringMismatch) { -- cgit v1.2.3