blob: 05f1e36f964a9780013990f11bd251bc1b3ca9d7 [file] [log] [blame]
Jan Tattermusch638a0812020-04-14 18:04:47 +02001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2015 Google Inc. All rights reserved.
4// https://developers.google.com/protocol-buffers/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31#endregion
32
33using NUnit.Framework;
34using System;
Jan Tattermusch638a0812020-04-14 18:04:47 +020035using System.Buffers;
Jan Tattermusch2bce0902020-06-03 14:36:39 +020036using Google.Protobuf.Buffers;
Jan Tattermusch638a0812020-04-14 18:04:47 +020037
38namespace Google.Protobuf
39{
40 public static class MessageParsingHelpers
41 {
42 public static void AssertReadingMessage<T>(MessageParser<T> parser, byte[] bytes, Action<T> assert) where T : IMessage<T>
43 {
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020044 var parsedMsg = parser.ParseFrom(bytes);
45 assert(parsedMsg);
Jan Tattermusch638a0812020-04-14 18:04:47 +020046
47 // Load content as single segment
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020048 parsedMsg = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
49 assert(parsedMsg);
Jan Tattermusch638a0812020-04-14 18:04:47 +020050
51 // Load content as multiple segments
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020052 parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
53 assert(parsedMsg);
Jan Tattermusch638a0812020-04-14 18:04:47 +020054
Jensaarai5095b682021-05-03 12:03:22 -070055 // Load content as ReadOnlySpan
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020056 parsedMsg = parser.ParseFrom(new ReadOnlySpan<byte>(bytes));
57 assert(parsedMsg);
Jan Tattermusch638a0812020-04-14 18:04:47 +020058 }
59
Jan Tattermusch238fd352020-04-15 10:08:19 +020060 public static void AssertReadingMessage(MessageParser parser, byte[] bytes, Action<IMessage> assert)
61 {
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020062 var parsedMsg = parser.ParseFrom(bytes);
63 assert(parsedMsg);
Jan Tattermusch238fd352020-04-15 10:08:19 +020064
65 // Load content as single segment
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020066 parsedMsg = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
67 assert(parsedMsg);
Jan Tattermusch238fd352020-04-15 10:08:19 +020068
69 // Load content as multiple segments
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020070 parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
71 assert(parsedMsg);
Jan Tattermuschf1d12ac2020-04-15 11:26:58 +020072
Jensaarai5095b682021-05-03 12:03:22 -070073 // Load content as ReadOnlySpan
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020074 parsedMsg = parser.ParseFrom(new ReadOnlySpan<byte>(bytes));
75 assert(parsedMsg);
Jan Tattermusch238fd352020-04-15 10:08:19 +020076 }
77
Jan Tattermusch638a0812020-04-14 18:04:47 +020078 public static void AssertReadingMessageThrows<TMessage, TException>(MessageParser<TMessage> parser, byte[] bytes)
79 where TMessage : IMessage<TMessage>
80 where TException : Exception
81 {
82 Assert.Throws<TException>(() => parser.ParseFrom(bytes));
83
84 Assert.Throws<TException>(() => parser.ParseFrom(new ReadOnlySequence<byte>(bytes)));
Jensaarai5095b682021-05-03 12:03:22 -070085
Jan Tattermusch89244fe2021-05-04 11:24:55 +020086 Assert.Throws<TException>(() => parser.ParseFrom(new ReadOnlySpan<byte>(bytes)));
Jan Tattermusch638a0812020-04-14 18:04:47 +020087 }
88
89 public static void AssertRoundtrip<T>(MessageParser<T> parser, T message, Action<T> additionalAssert = null) where T : IMessage<T>
90 {
91 var bytes = message.ToByteArray();
92
Jan Tattermusch2bce0902020-06-03 14:36:39 +020093 // also serialize using IBufferWriter and check it leads to the same data
James Newton-King89324462020-12-16 12:56:14 +130094 var bufferWriter = new TestArrayBufferWriter<byte>();
Jan Tattermusch2bce0902020-06-03 14:36:39 +020095 message.WriteTo(bufferWriter);
96 Assert.AreEqual(bytes, bufferWriter.WrittenSpan.ToArray(), "Both serialization approaches need to result in the same data.");
97
Jan Tattermusch2f0e2692021-05-04 11:39:15 +020098 var parsedMsg = parser.ParseFrom(bytes);
99 Assert.AreEqual(message, parsedMsg);
100 additionalAssert?.Invoke(parsedMsg);
Jensaarai5095b682021-05-03 12:03:22 -0700101
Jan Tattermusch638a0812020-04-14 18:04:47 +0200102 // Load content as single segment
Jan Tattermusch2f0e2692021-05-04 11:39:15 +0200103 parsedMsg = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
104 Assert.AreEqual(message, parsedMsg);
105 additionalAssert?.Invoke(parsedMsg);
Jan Tattermusch638a0812020-04-14 18:04:47 +0200106
107 // Load content as multiple segments
Jan Tattermusch2f0e2692021-05-04 11:39:15 +0200108 parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
109 Assert.AreEqual(message, parsedMsg);
110 additionalAssert?.Invoke(parsedMsg);
Jan Tattermusch638a0812020-04-14 18:04:47 +0200111
Jensaarai5095b682021-05-03 12:03:22 -0700112 // Load content as ReadOnlySpan
Jan Tattermusch2f0e2692021-05-04 11:39:15 +0200113 parsedMsg = parser.ParseFrom(new ReadOnlySpan<byte>(bytes));
114 Assert.AreEqual(message, parsedMsg);
115 additionalAssert?.Invoke(parsedMsg);
Jan Tattermusch638a0812020-04-14 18:04:47 +0200116 }
Jan Tattermusch2bce0902020-06-03 14:36:39 +0200117
118 public static void AssertWritingMessage(IMessage message)
119 {
120 // serialize using CodedOutputStream
121 var bytes = message.ToByteArray();
122
Jan Tattermuschb3cdba12020-06-03 15:50:07 +0200123 int messageSize = message.CalculateSize();
124 Assert.AreEqual(message.CalculateSize(), bytes.Length);
125
126 // serialize using IBufferWriter and check it leads to the same output
James Newton-King89324462020-12-16 12:56:14 +1300127 var bufferWriter = new TestArrayBufferWriter<byte>();
Jan Tattermusch2bce0902020-06-03 14:36:39 +0200128 message.WriteTo(bufferWriter);
Jan Tattermuschb3cdba12020-06-03 15:50:07 +0200129 Assert.AreEqual(bytes, bufferWriter.WrittenSpan.ToArray());
Jan Tattermusch2bce0902020-06-03 14:36:39 +0200130
Jan Tattermuschb3cdba12020-06-03 15:50:07 +0200131 // serialize into a single span and check it leads to the same output
132 var singleSpan = new Span<byte>(new byte[messageSize]);
133 message.WriteTo(singleSpan);
134 Assert.AreEqual(bytes, singleSpan.ToArray());
Jan Tattermusch8dbf7072020-06-03 14:47:55 +0200135
Jan Tattermusche14a5c82020-06-08 16:23:33 +0200136 // test for different IBufferWriter.GetSpan() segment sizes
137 for (int blockSize = 1; blockSize < 256; blockSize *= 2)
138 {
James Newton-King89324462020-12-16 12:56:14 +1300139 var segmentedBufferWriter = new TestArrayBufferWriter<byte>();
Jan Tattermusche14a5c82020-06-08 16:23:33 +0200140 segmentedBufferWriter.MaxGrowBy = blockSize;
141 message.WriteTo(segmentedBufferWriter);
Jan Tattermusch53708e22020-06-08 17:03:03 +0200142 Assert.AreEqual(bytes, segmentedBufferWriter.WrittenSpan.ToArray());
143 }
144
145 // if the full message is small enough, try serializing directly into stack-allocated buffer
146 if (bytes.Length <= 256)
147 {
148 Span<byte> stackAllocBuffer = stackalloc byte[bytes.Length];
149 message.WriteTo(stackAllocBuffer);
150 Assert.AreEqual(bytes, stackAllocBuffer.ToArray());
Jan Tattermusche14a5c82020-06-08 16:23:33 +0200151 }
Jan Tattermusch2bce0902020-06-03 14:36:39 +0200152 }
Jan Tattermusch638a0812020-04-14 18:04:47 +0200153 }
154}