Skip to content

Commit

Permalink
Merge pull request #7491 from haberman/cherry
Browse files Browse the repository at this point in the history
Cherry-pick fixes onto 3.12.x branch for 3.12.0-rc2
  • Loading branch information
haberman committed May 12, 2020
2 parents d001f8c + 01e8c0f commit 51199fc
Show file tree
Hide file tree
Showing 25 changed files with 931 additions and 1,095 deletions.
142 changes: 40 additions & 102 deletions csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs

Large diffs are not rendered by default.

924 changes: 261 additions & 663 deletions csharp/src/Google.Protobuf.Test.TestProtos/Unittest.cs

Large diffs are not rendered by default.

150 changes: 88 additions & 62 deletions csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs

Large diffs are not rendered by default.

171 changes: 151 additions & 20 deletions csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs
Expand Up @@ -98,44 +98,112 @@ public void GetValue_IncorrectType()
}

[Test]
public void HasValue_Proto3()
public void HasValue_Proto3_Message()
{
var message = new TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.SingleForeignMessageFieldNumber].Accessor;
Assert.False(accessor.HasValue(message));
message.SingleForeignMessage = new ForeignMessage();
Assert.True(accessor.HasValue(message));
message.SingleForeignMessage = null;
Assert.False(accessor.HasValue(message));
}

[Test]
public void HasValue_Proto3_Oneof()
{
TestAllTypes message = new TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.OneofStringFieldNumber].Accessor;
Assert.False(accessor.HasValue(message));
// Even though it's the default value, we still have a value.
message.OneofString = "";
Assert.True(accessor.HasValue(message));
message.OneofString = "hello";
Assert.True(accessor.HasValue(message));
message.OneofUint32 = 10;
Assert.False(accessor.HasValue(message));
}

[Test]
public void HasValue_Proto3_Primitive_Optional()
{
var message = new TestProto3Optional();
var accessor = ((IMessage) message).Descriptor.Fields[TestProto3Optional.OptionalInt64FieldNumber].Accessor;
Assert.IsFalse(accessor.HasValue(message));
message.OptionalInt64 = 5L;
Assert.IsTrue(accessor.HasValue(message));
message.ClearOptionalInt64();
Assert.IsFalse(accessor.HasValue(message));
message.OptionalInt64 = 0L;
Assert.IsTrue(accessor.HasValue(message));
}

[Test]
public void HasValue_Proto3_Primitive_NotOptional()
{
IMessage message = SampleMessages.CreateFullTestAllTypes();
var fields = message.Descriptor.Fields;
Assert.Throws<InvalidOperationException>(() => fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.HasValue(message));
}

[Test]
public void HasValue_Proto3Optional()
public void HasValue_Proto3_Repeated()
{
IMessage message = new TestProto3Optional
{
OptionalInt32 = 0,
LazyNestedMessage = new TestProto3Optional.Types.NestedMessage()
};
var fields = message.Descriptor.Fields;
Assert.IsFalse(fields[TestProto3Optional.OptionalInt64FieldNumber].Accessor.HasValue(message));
Assert.IsFalse(fields[TestProto3Optional.OptionalNestedMessageFieldNumber].Accessor.HasValue(message));
Assert.IsTrue(fields[TestProto3Optional.LazyNestedMessageFieldNumber].Accessor.HasValue(message));
Assert.IsTrue(fields[TestProto3Optional.OptionalInt32FieldNumber].Accessor.HasValue(message));
var message = new TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.RepeatedBoolFieldNumber].Accessor;
Assert.Throws<InvalidOperationException>(() => accessor.HasValue(message));
}

[Test]
public void HasValue()
public void HasValue_Proto2_Primitive()
{
IMessage message = new Proto2.TestAllTypes();
var fields = message.Descriptor.Fields;
var accessor = fields[Proto2.TestAllTypes.OptionalBoolFieldNumber].Accessor;
var message = new Proto2.TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OptionalInt64FieldNumber].Accessor;

Assert.IsFalse(accessor.HasValue(message));
message.OptionalInt64 = 5L;
Assert.IsTrue(accessor.HasValue(message));
message.ClearOptionalInt64();
Assert.IsFalse(accessor.HasValue(message));
message.OptionalInt64 = 0L;
Assert.IsTrue(accessor.HasValue(message));
}

Assert.False(accessor.HasValue(message));
[Test]
public void HasValue_Proto2_Message()
{
var message = new Proto2.TestAllTypes();
var field = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OptionalForeignMessageFieldNumber];
Assert.False(field.Accessor.HasValue(message));
message.OptionalForeignMessage = new Proto2.ForeignMessage();
Assert.True(field.Accessor.HasValue(message));
message.OptionalForeignMessage = null;
Assert.False(field.Accessor.HasValue(message));
}

accessor.SetValue(message, true);
[Test]
public void HasValue_Proto2_Oneof()
{
var message = new Proto2.TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OneofStringFieldNumber].Accessor;
Assert.False(accessor.HasValue(message));
// Even though it's the default value, we still have a value.
message.OneofString = "";
Assert.True(accessor.HasValue(message));

accessor.Clear(message);
message.OneofString = "hello";
Assert.True(accessor.HasValue(message));
message.OneofUint32 = 10;
Assert.False(accessor.HasValue(message));
}

[Test]
public void HasValue_Proto2_Repeated()
{
var message = new Proto2.TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.RepeatedBoolFieldNumber].Accessor;
Assert.Throws<InvalidOperationException>(() => accessor.HasValue(message));
}

[Test]
public void SetValue_SingleFields()
{
Expand Down Expand Up @@ -262,6 +330,42 @@ public void Clear_Proto3Optional()
Assert.Null(message.OptionalNestedMessage);
}

[Test]
public void Clear_Proto3_Oneof()
{
var message = new TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.OneofUint32FieldNumber].Accessor;

// The field accessor Clear method only affects a oneof if the current case is the one being cleared.
message.OneofString = "hello";
Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase);
accessor.Clear(message);
Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase);

message.OneofUint32 = 100;
Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase);
accessor.Clear(message);
Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
}

[Test]
public void Clear_Proto2_Oneof()
{
var message = new Proto2.TestAllTypes();
var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OneofUint32FieldNumber].Accessor;

// The field accessor Clear method only affects a oneof if the current case is the one being cleared.
message.OneofString = "hello";
Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase);
accessor.Clear(message);
Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase);

message.OneofUint32 = 100;
Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase);
accessor.Clear(message);
Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
}

[Test]
public void FieldDescriptor_ByName()
{
Expand Down Expand Up @@ -301,5 +405,32 @@ public void GetRepeatedExtensionValue()
message.ClearExtension(RepeatedBoolExtension);
Assert.IsNull(message.GetExtension(RepeatedBoolExtension));
}

[Test]
public void HasPresence()
{
// Proto3
var fields = TestProtos.TestAllTypes.Descriptor.Fields;
Assert.IsFalse(fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].HasPresence);
Assert.IsTrue(fields[TestProtos.TestAllTypes.OneofBytesFieldNumber].HasPresence);
Assert.IsTrue(fields[TestProtos.TestAllTypes.SingleForeignMessageFieldNumber].HasPresence);
Assert.IsFalse(fields[TestProtos.TestAllTypes.RepeatedBoolFieldNumber].HasPresence);

fields = TestMap.Descriptor.Fields;
Assert.IsFalse(fields[TestMap.MapBoolBoolFieldNumber].HasPresence);

fields = TestProto3Optional.Descriptor.Fields;
Assert.IsTrue(fields[TestProto3Optional.OptionalBoolFieldNumber].HasPresence);

// Proto2
fields = Proto2.TestAllTypes.Descriptor.Fields;
Assert.IsTrue(fields[Proto2.TestAllTypes.OptionalBoolFieldNumber].HasPresence);
Assert.IsTrue(fields[Proto2.TestAllTypes.OneofBytesFieldNumber].HasPresence);
Assert.IsTrue(fields[Proto2.TestAllTypes.OptionalForeignMessageFieldNumber].HasPresence);
Assert.IsFalse(fields[Proto2.TestAllTypes.RepeatedBoolFieldNumber].HasPresence);

fields = Proto2.TestRequired.Descriptor.Fields;
Assert.IsTrue(fields[Proto2.TestRequired.AFieldNumber].HasPresence);
}
}
}
6 changes: 6 additions & 0 deletions csharp/src/Google.Protobuf/Extension.cs
Expand Up @@ -55,6 +55,8 @@ protected Extension(int fieldNumber)
/// Gets the field number of this extension
/// </summary>
public int FieldNumber { get; }

internal abstract bool IsRepeated { get; }
}

/// <summary>
Expand All @@ -79,6 +81,8 @@ public Extension(int fieldNumber, FieldCodec<TValue> codec) : base(fieldNumber)

internal override Type TargetType => typeof(TTarget);

internal override bool IsRepeated => false;

internal override IExtensionValue CreateValue()
{
return new ExtensionValue<TValue>(codec);
Expand All @@ -105,6 +109,8 @@ public RepeatedExtension(int fieldNumber, FieldCodec<TValue> codec) : base(field

internal override Type TargetType => typeof(TTarget);

internal override bool IsRepeated => true;

internal override IExtensionValue CreateValue()
{
return new RepeatedExtensionValue<TValue>(codec);
Expand Down

0 comments on commit 51199fc

Please sign in to comment.