#region Copyright notice and license // Protocol Buffers - Google's data interchange format // Copyright 2015 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #endregion using NUnit.Framework; using System; using System.Buffers; using Google.Protobuf.Buffers; namespace Google.Protobuf { public static class MessageParsingHelpers { public static void AssertReadingMessage(MessageParser parser, byte[] bytes, Action assert) where T : IMessage { var parsedMsg = parser.ParseFrom(bytes); assert(parsedMsg); // Load content as single segment parsedMsg = parser.ParseFrom(new ReadOnlySequence(bytes)); assert(parsedMsg); // Load content as multiple segments parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes)); assert(parsedMsg); // Load content as ReadOnlySpan parsedMsg = parser.ParseFrom(new ReadOnlySpan(bytes)); assert(parsedMsg); } public static void AssertReadingMessage(MessageParser parser, byte[] bytes, Action assert) { var parsedMsg = parser.ParseFrom(bytes); assert(parsedMsg); // Load content as single segment parsedMsg = parser.ParseFrom(new ReadOnlySequence(bytes)); assert(parsedMsg); // Load content as multiple segments parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes)); assert(parsedMsg); // Load content as ReadOnlySpan parsedMsg = parser.ParseFrom(new ReadOnlySpan(bytes)); assert(parsedMsg); } public static void AssertReadingMessageThrows(MessageParser parser, byte[] bytes) where TMessage : IMessage where TException : Exception { Assert.Throws(() => parser.ParseFrom(bytes)); Assert.Throws(() => parser.ParseFrom(new ReadOnlySequence(bytes))); Assert.Throws(() => parser.ParseFrom(new ReadOnlySpan(bytes))); } public static void AssertRoundtrip(MessageParser parser, T message, Action additionalAssert = null) where T : IMessage { var bytes = message.ToByteArray(); // also serialize using IBufferWriter and check it leads to the same data var bufferWriter = new TestArrayBufferWriter(); message.WriteTo(bufferWriter); Assert.AreEqual(bytes, bufferWriter.WrittenSpan.ToArray(), "Both serialization approaches need to result in the same data."); var parsedMsg = parser.ParseFrom(bytes); Assert.AreEqual(message, parsedMsg); additionalAssert?.Invoke(parsedMsg); // Load content as single segment parsedMsg = parser.ParseFrom(new ReadOnlySequence(bytes)); Assert.AreEqual(message, parsedMsg); additionalAssert?.Invoke(parsedMsg); // Load content as multiple segments parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes)); Assert.AreEqual(message, parsedMsg); additionalAssert?.Invoke(parsedMsg); // Load content as ReadOnlySpan parsedMsg = parser.ParseFrom(new ReadOnlySpan(bytes)); Assert.AreEqual(message, parsedMsg); additionalAssert?.Invoke(parsedMsg); } public static void AssertWritingMessage(IMessage message) { // serialize using CodedOutputStream var bytes = message.ToByteArray(); int messageSize = message.CalculateSize(); Assert.AreEqual(message.CalculateSize(), bytes.Length); // serialize using IBufferWriter and check it leads to the same output var bufferWriter = new TestArrayBufferWriter(); message.WriteTo(bufferWriter); Assert.AreEqual(bytes, bufferWriter.WrittenSpan.ToArray()); // serialize into a single span and check it leads to the same output var singleSpan = new Span(new byte[messageSize]); message.WriteTo(singleSpan); Assert.AreEqual(bytes, singleSpan.ToArray()); // test for different IBufferWriter.GetSpan() segment sizes for (int blockSize = 1; blockSize < 256; blockSize *= 2) { var segmentedBufferWriter = new TestArrayBufferWriter { MaxGrowBy = blockSize }; message.WriteTo(segmentedBufferWriter); Assert.AreEqual(bytes, segmentedBufferWriter.WrittenSpan.ToArray()); } // if the full message is small enough, try serializing directly into stack-allocated buffer if (bytes.Length <= 256) { Span stackAllocBuffer = stackalloc byte[bytes.Length]; message.WriteTo(stackAllocBuffer); Assert.AreEqual(bytes, stackAllocBuffer.ToArray()); } } } }