riyowry / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
Other
0 stars 0 forks source link

Invalid behaviour while deserializing unknown enum value #422

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
This test describes expected behaviour. The equivalent test works in c++, java.
This test worked well with protobuf-net v1, but it was broken when we got 
protobuf-net v2: we got an exception ProtoBuf.ProtoException : No 
Tests.Enum_Test+E1 enum is mapped to the wire-value 3

[TestFixture]
public class Enum_Test
{
    [ProtoContract]
    public enum E1
    {
        [ProtoEnum(Value = 0)] Default = 0,
        [ProtoEnum(Value = 1)] One = 1,
        [ProtoEnum(Value = 2)] Two = 2
    }
    [ProtoContract]
    public class Dummy1 : IExtensible
    {
        [ProtoMember(1, IsRequired = false)]
        [DefaultValue(E1.Default)]
        public E1 EnumProp { get; set; }

        private IExtension extensionObject;
        IExtension IExtensible.GetExtensionObject(bool createIfMissing)
        {
            return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
        }
    }
    [ProtoContract]
    public enum E2
    {
        [ProtoEnum(Value = 0)] Default = 0,
        [ProtoEnum(Value = 1)] One = 1,
        [ProtoEnum(Value = 2)] Two = 2,
        [ProtoEnum(Value = 3)] Three = 3
    }
    [ProtoContract]
    public class Dummy2
    {
        [ProtoMember(1, IsRequired = false)]
        [DefaultValue(E2.Default)]
        public E2 EnumProp { get; set; }
    }
    [Test]
    public void MissingEnumValueDeserializationSuccess()
    {
        var dummy2 = new Dummy2 { EnumProp = E2.Three };
        var bytes = dummy2.ToProtoBytes();
        var dummy1 = bytes.FromProtoBytes<Dummy1>();
        Assert.AreEqual(E1.Default, dummy1.EnumProp);
    }
}

good version: protobuf-net r282 (windows 7 x64)
buggy version: protobuf-net r668 (windows 7 x64)

Original issue reported on code.google.com by space...@yandex.ru on 19 Dec 2013 at 9:51

GoogleCodeExporter commented 8 years ago
I'm also seeing this invalid behaviour. An unknown enum value should be treated 
like an unknown field or have it's default value set.

Original comment by felixbr...@gmail.com on 27 Jan 2014 at 2:50

GoogleCodeExporter commented 8 years ago
I looked at the code in an attempt to fix this for myself locally, and see in 
the EnumSerializer.cs 

public object Read(object value, ProtoReader source)
{
    Helpers.DebugAssert(value == null); // since replaces
    int wireValue = source.ReadInt32();
    if(map == null) {
        return WireToEnum(wireValue);
    }
    for(int i = 0 ; i < map.Length ; i++) {
        if(map[i].WireValue == wireValue) {
            return map[i].TypedValue;
            }
        }
    source.ThrowEnumException(ExpectedType, wireValue);
    return null; // to make compiler happy
}

Instead of throwing the enum exception at the end, it should just return null. 
The level above it has a check for null and will assign the default value.

This works for me in debug versions, but i can't get the EnumSerializer to 
compile in release, because i don't understand how the CompiledSerializer works.

Just my 2 cents on this in case it helps anyone identify the issue.

Original comment by chrisher...@gmail.com on 30 Apr 2014 at 11:24

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
Thanks for proposed code, i can confirm it works! This is also how Java and C++ 
protobuffer handles undefined enums, that it will fallback to default value, 
instead of throwing exception.

Original comment by noxx...@googlemail.com on 30 May 2014 at 2:23