• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc.  All rights reserved.
4 //
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file or at
7 // https://developers.google.com/open-source/licenses/bsd
8 #endregion
9 
10 using NUnit.Framework;
11 using System;
12 using System.Buffers;
13 using Google.Protobuf.Buffers;
14 
15 namespace Google.Protobuf
16 {
17     public static class MessageParsingHelpers
18     {
19         public static void AssertReadingMessage<T>(MessageParser<T> parser, byte[] bytes, Action<T> assert) where T : IMessage<T>
20         {
21             var parsedMsg = parser.ParseFrom(bytes);
22             assert(parsedMsg);
23 
24             // Load content as single segment
25             parsedMsg = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
26             assert(parsedMsg);
27 
28             // Load content as multiple segments
29             parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
30             assert(parsedMsg);
31 
32             // Load content as ReadOnlySpan
33             parsedMsg = parser.ParseFrom(new ReadOnlySpan<byte>(bytes));
34             assert(parsedMsg);
35         }
36 
AssertReadingMessage(MessageParser parser, byte[] bytes, Action<IMessage> assert)37         public static void AssertReadingMessage(MessageParser parser, byte[] bytes, Action<IMessage> assert)
38         {
39             var parsedMsg = parser.ParseFrom(bytes);
40             assert(parsedMsg);
41 
42             // Load content as single segment
43             parsedMsg = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
44             assert(parsedMsg);
45 
46             // Load content as multiple segments
47             parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
48             assert(parsedMsg);
49 
50             // Load content as ReadOnlySpan
51             parsedMsg = parser.ParseFrom(new ReadOnlySpan<byte>(bytes));
52             assert(parsedMsg);
53         }
54 
55         public static void AssertReadingMessageThrows<TMessage, TException>(MessageParser<TMessage> parser, byte[] bytes)
56             where TMessage : IMessage<TMessage>
57             where TException : Exception
58         {
59             Assert.Throws<TException>(() => parser.ParseFrom(bytes));
60 
61             Assert.Throws<TException>(() => parser.ParseFrom(new ReadOnlySequence<byte>(bytes)));
62 
63             Assert.Throws<TException>(() => parser.ParseFrom(new ReadOnlySpan<byte>(bytes)));
64         }
65 
66         public static void AssertRoundtrip<T>(MessageParser<T> parser, T message, Action<T> additionalAssert = null) where T : IMessage<T>
67         {
68             var bytes = message.ToByteArray();
69 
70             // also serialize using IBufferWriter and check it leads to the same data
71             var bufferWriter = new TestArrayBufferWriter<byte>();
72             message.WriteTo(bufferWriter);
73             Assert.AreEqual(bytes, bufferWriter.WrittenSpan.ToArray(), "Both serialization approaches need to result in the same data.");
74 
75             var parsedMsg = parser.ParseFrom(bytes);
76             Assert.AreEqual(message, parsedMsg);
77             additionalAssert?.Invoke(parsedMsg);
78 
79             // Load content as single segment
80             parsedMsg = parser.ParseFrom(new ReadOnlySequence<byte>(bytes));
81             Assert.AreEqual(message, parsedMsg);
82             additionalAssert?.Invoke(parsedMsg);
83 
84             // Load content as multiple segments
85             parsedMsg = parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(bytes));
86             Assert.AreEqual(message, parsedMsg);
87             additionalAssert?.Invoke(parsedMsg);
88 
89             // Load content as ReadOnlySpan
90             parsedMsg = parser.ParseFrom(new ReadOnlySpan<byte>(bytes));
91             Assert.AreEqual(message, parsedMsg);
92             additionalAssert?.Invoke(parsedMsg);
93         }
94 
AssertWritingMessage(IMessage message)95         public static void AssertWritingMessage(IMessage message)
96         {
97             // serialize using CodedOutputStream
98             var bytes = message.ToByteArray();
99 
100             int messageSize = message.CalculateSize();
101             Assert.AreEqual(message.CalculateSize(), bytes.Length);
102 
103             // serialize using IBufferWriter and check it leads to the same output
104             var bufferWriter = new TestArrayBufferWriter<byte>();
105             message.WriteTo(bufferWriter);
106             Assert.AreEqual(bytes, bufferWriter.WrittenSpan.ToArray());
107 
108             // serialize into a single span and check it leads to the same output
109             var singleSpan = new Span<byte>(new byte[messageSize]);
110             message.WriteTo(singleSpan);
111             Assert.AreEqual(bytes, singleSpan.ToArray());
112 
113             // test for different IBufferWriter.GetSpan() segment sizes
114             for (int blockSize = 1; blockSize < 256; blockSize *= 2)
115             {
116                 var segmentedBufferWriter = new TestArrayBufferWriter<byte> { MaxGrowBy = blockSize };
117                 message.WriteTo(segmentedBufferWriter);
118                 Assert.AreEqual(bytes, segmentedBufferWriter.WrittenSpan.ToArray());
119             }
120 
121             // if the full message is small enough, try serializing directly into stack-allocated buffer
122             if (bytes.Length <= 256)
123             {
124                 Span<byte> stackAllocBuffer = stackalloc byte[bytes.Length];
125                 message.WriteTo(stackAllocBuffer);
126                 Assert.AreEqual(bytes, stackAllocBuffer.ToArray());
127             }
128         }
129     }
130 }