parent
c2925d5b93
commit
638a0813b4
3 changed files with 312 additions and 44 deletions
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue