increase coverage of GeneratedMessageTest
diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
index 103df7d..3499e66 100644
--- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
+++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
@@ -131,8 +131,8 @@
// Without setting any values, there's nothing to write.
byte[] bytes = message.ToByteArray();
Assert.AreEqual(0, bytes.Length);
- TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes);
- Assert.AreEqual(message, parsed);
+
+ MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message);
}
[Test]
@@ -165,8 +165,8 @@
};
byte[] bytes = message.ToByteArray();
- TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes);
- Assert.AreEqual(message, parsed);
+
+ MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message);
}
[Test]
@@ -199,8 +199,8 @@
};
byte[] bytes = message.ToByteArray();
- TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes);
- Assert.AreEqual(message, parsed);
+
+ MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message);
}
// Note that not every map within map_unittest_proto3 is used. They all go through very
@@ -231,8 +231,8 @@
};
byte[] bytes = message.ToByteArray();
- TestMap parsed = TestMap.Parser.ParseFrom(bytes);
- Assert.AreEqual(message, parsed);
+
+ MessageParsingHelpers.AssertRoundtrip(TestMap.Parser, message);
}
[Test]
@@ -246,9 +246,14 @@
byte[] bytes = message.ToByteArray();
Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte)
- var parsed = TestMap.Parser.ParseFrom(bytes);
- Assert.AreEqual(1, parsed.MapInt32Bytes.Count);
- Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ bytes,
+ parsed=>
+ {
+ Assert.AreEqual(1, parsed.MapInt32Bytes.Count);
+ Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]);
+ });
}
[Test]
@@ -265,8 +270,13 @@
output.WriteMessage(nestedMessage);
output.Flush();
- var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
- Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ memoryStream.ToArray(),
+ parsed =>
+ {
+ Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]);
+ });
}
[Test]
@@ -282,8 +292,13 @@
output.WriteInt32(key);
output.Flush();
- var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
- Assert.AreEqual(0.0, parsed.MapInt32Double[key]);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ memoryStream.ToArray(),
+ parsed =>
+ {
+ Assert.AreEqual(0.0, parsed.MapInt32Double[key]);
+ });
}
[Test]
@@ -299,8 +314,13 @@
output.WriteInt32(key);
output.Flush();
- var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
- Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ memoryStream.ToArray(),
+ parsed =>
+ {
+ Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]);
+ });
}
[Test]
@@ -327,8 +347,13 @@
output.WriteInt32(extra);
output.Flush();
- var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
- Assert.AreEqual(value, parsed.MapInt32Int32[key]);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ memoryStream.ToArray(),
+ parsed =>
+ {
+ Assert.AreEqual(value, parsed.MapInt32Int32[key]);
+ });
}
[Test]
@@ -351,8 +376,13 @@
output.WriteInt32(key);
output.Flush();
- var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
- Assert.AreEqual(value, parsed.MapInt32Int32[key]);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ memoryStream.ToArray(),
+ parsed =>
+ {
+ Assert.AreEqual(value, parsed.MapInt32Int32[key]);
+ });
}
[Test]
@@ -397,13 +427,19 @@
output.WriteInt32(value3);
output.Flush();
- var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
- var expected = new TestMap
- {
- MapInt32Int32 = { { key1, value1 }, { key3, value3 } },
- MapStringString = { { key2, value2 } }
- };
- Assert.AreEqual(expected, parsed);
+
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ memoryStream.ToArray(),
+ parsed =>
+ {
+ var expected = new TestMap
+ {
+ MapInt32Int32 = { { key1, value1 }, { key3, value3 } },
+ MapStringString = { { key2, value2 } }
+ };
+ Assert.AreEqual(expected, parsed);
+ });
}
[Test]
@@ -433,8 +469,13 @@
output.WriteInt32(value2);
output.Flush();
- var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
- Assert.AreEqual(value2, parsed.MapInt32Int32[key]);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestMap.Parser,
+ memoryStream.ToArray(),
+ parsed =>
+ {
+ Assert.AreEqual(value2, parsed.MapInt32Int32[key]);
+ });
}
[Test]
@@ -619,9 +660,10 @@
var bytes = message.ToByteArray();
Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string!
- var message2 = TestAllTypes.Parser.ParseFrom(bytes);
- Assert.AreEqual(message, message2);
- Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);
+ MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage =>
+ {
+ Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase);
+ });
}
[Test]
@@ -633,9 +675,10 @@
var bytes = message.ToByteArray();
Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized
- var message2 = TestAllTypes.Parser.ParseFrom(bytes);
- Assert.AreEqual(message, message2);
- Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);
+ MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage =>
+ {
+ Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase);
+ });
}
[Test]
@@ -651,10 +694,14 @@
message.WriteTo(output);
output.Flush();
- stream.Position = 0;
- var parsed = TestAllTypes.Parser.ParseFrom(stream);
- // TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
- // Assert.AreEqual(message, parsed);
+ MessageParsingHelpers.AssertReadingMessage(
+ TestAllTypes.Parser,
+ stream.ToArray(),
+ parsed =>
+ {
+ // TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
+ // Assert.AreEqual(message, parsed);
+ });
}
[Test]
@@ -663,8 +710,15 @@
// Simple way of ensuring we can skip all kinds of fields.
var data = SampleMessages.CreateFullTestAllTypes().ToByteArray();
var empty = Empty.Parser.ParseFrom(data);
- // TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
- // Assert.AreNotEqual(new Empty(), empty);
+
+ MessageParsingHelpers.AssertReadingMessage(
+ Empty.Parser,
+ data,
+ parsed =>
+ {
+ // TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
+ // Assert.AreNotEqual(new Empty(), empty);
+ });
}
// This was originally seen as a conformance test failure.
@@ -674,7 +728,7 @@
// 130, 3 is the message tag
// 1 is the data length - but there's no data.
var data = new byte[] { 130, 3, 1 };
- Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(data));
+ MessageParsingHelpers.AssertReadingMessageThrows<TestAllTypes, InvalidProtocolBufferException>(TestAllTypes.Parser, data);
}
/// <summary>
@@ -695,7 +749,7 @@
output.Flush();
stream.Position = 0;
- Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream));
+ MessageParsingHelpers.AssertReadingMessageThrows<TestAllTypes, InvalidProtocolBufferException>(TestAllTypes.Parser, stream.ToArray());
}
[Test]
diff --git a/csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs b/csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs
new file mode 100644
index 0000000..d629d9c
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs
@@ -0,0 +1,86 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using NUnit.Framework;
+using System;
+using Google.Protobuf.Buffers;
+using System.Buffers;
+
+namespace Google.Protobuf
+{
+ public static class MessageParsingHelpers
+ {
+ public static void AssertReadingMessage<T>(MessageParser<T> parser, byte[] bytes, Action<T> assert) where T : IMessage<T>
+ {
+ var parsedStream = parser.ParseFrom(bytes);
+
+ // Load content as single segment
+ var parsedBuffer = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
+ assert(parsedBuffer);
+
+ // Load content as multiple segments
+ parsedBuffer = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
+ assert(parsedBuffer);
+
+ assert(parsedStream);
+ }
+
+ public static void AssertReadingMessageThrows<TMessage, TException>(MessageParser<TMessage> parser, byte[] bytes)
+ where TMessage : IMessage<TMessage>
+ where TException : Exception
+ {
+ Assert.Throws<TException>(() => parser.ParseFrom(bytes));
+
+ Assert.Throws<TException>(() => parser.ParseFrom(new ReadOnlySequence<byte>(bytes)));
+ }
+
+ public static void AssertRoundtrip<T>(MessageParser<T> parser, T message, Action<T> additionalAssert = null) where T : IMessage<T>
+ {
+ var bytes = message.ToByteArray();
+
+ // Load content as single segment
+ var parsedBuffer = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
+ Assert.AreEqual(message, parsedBuffer);
+ additionalAssert?.Invoke(parsedBuffer);
+
+ // Load content as multiple segments
+ parsedBuffer = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
+ Assert.AreEqual(message, parsedBuffer);
+ additionalAssert?.Invoke(parsedBuffer);
+
+ var parsedStream = parser.ParseFrom(bytes);
+
+ Assert.AreEqual(message, parsedStream);
+ additionalAssert?.Invoke(parsedStream);
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs b/csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs
new file mode 100644
index 0000000..f35844c
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs
@@ -0,0 +1,128 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Google.Protobuf.Buffers
+{
+ internal static class ReadOnlySequenceFactory
+ {
+ public static ReadOnlySequence<byte> CreateWithContent(byte[] data, int segmentSize = 1)
+ {
+ var segments = new List<byte[]>();
+
+ segments.Add(new byte[0]);
+ var currentIndex = 0;
+ while (currentIndex < data.Length)
+ {
+ var segment = new List<byte>();
+ for (; currentIndex < Math.Min(currentIndex + segmentSize, data.Length); currentIndex++)
+ {
+ segment.Add(data[currentIndex]);
+ }
+ segments.Add(segment.ToArray());
+ segments.Add(new byte[0]);
+ }
+
+ return CreateSegments(segments.ToArray());
+ }
+
+ /// <summary>
+ /// Originally from corefx, and has been contributed to Protobuf
+ /// https://github.com/dotnet/corefx/blob/e99ec129cfd594d53f4390bf97d1d736cff6f860/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs
+ /// </summary>
+ private static ReadOnlySequence<byte> CreateSegments(params byte[][] inputs)
+ {
+ if (inputs == null || inputs.Length == 0)
+ {
+ throw new InvalidOperationException();
+ }
+
+ int i = 0;
+
+ BufferSegment last = null;
+ BufferSegment first = null;
+
+ do
+ {
+ byte[] s = inputs[i];
+ int length = s.Length;
+ int dataOffset = length;
+ var chars = new byte[length * 2];
+
+ for (int j = 0; j < length; j++)
+ {
+ chars[dataOffset + j] = s[j];
+ }
+
+ // Create a segment that has offset relative to the OwnedMemory and OwnedMemory itself has offset relative to array
+ var memory = new Memory<byte>(chars).Slice(length, length);
+
+ if (first == null)
+ {
+ first = new BufferSegment(memory);
+ last = first;
+ }
+ else
+ {
+ last = last.Append(memory);
+ }
+ i++;
+ } while (i < inputs.Length);
+
+ return new ReadOnlySequence<byte>(first, 0, last, last.Memory.Length);
+ }
+
+ private class BufferSegment : ReadOnlySequenceSegment<byte>
+ {
+ public BufferSegment(Memory<byte> memory)
+ {
+ Memory = memory;
+ }
+
+ public BufferSegment Append(Memory<byte> memory)
+ {
+ var segment = new BufferSegment(memory)
+ {
+ RunningIndex = RunningIndex + Memory.Length
+ };
+ Next = segment;
+ return segment;
+ }
+ }
+ }
+}
\ No newline at end of file