xref: /aosp_15_r20/external/protobuf/csharp/src/Google.Protobuf.Test/ByteStringTest.cs (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license
2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format
3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2008 Google Inc.  All rights reserved.
4*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/
5*1b3f573fSAndroid Build Coastguard Worker //
6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
8*1b3f573fSAndroid Build Coastguard Worker // met:
9*1b3f573fSAndroid Build Coastguard Worker //
10*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions of source code must retain the above copyright
11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
12*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions in binary form must reproduce the above
13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
15*1b3f573fSAndroid Build Coastguard Worker // distribution.
16*1b3f573fSAndroid Build Coastguard Worker //     * Neither the name of Google Inc. nor the names of its
17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission.
19*1b3f573fSAndroid Build Coastguard Worker //
20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*1b3f573fSAndroid Build Coastguard Worker #endregion
32*1b3f573fSAndroid Build Coastguard Worker 
33*1b3f573fSAndroid Build Coastguard Worker using System;
34*1b3f573fSAndroid Build Coastguard Worker using System.Text;
35*1b3f573fSAndroid Build Coastguard Worker using NUnit.Framework;
36*1b3f573fSAndroid Build Coastguard Worker using System.IO;
37*1b3f573fSAndroid Build Coastguard Worker using System.Collections.Generic;
38*1b3f573fSAndroid Build Coastguard Worker using System.Collections;
39*1b3f573fSAndroid Build Coastguard Worker using System.Linq;
40*1b3f573fSAndroid Build Coastguard Worker using System.Buffers;
41*1b3f573fSAndroid Build Coastguard Worker using System.Runtime.InteropServices;
42*1b3f573fSAndroid Build Coastguard Worker using System.Threading;
43*1b3f573fSAndroid Build Coastguard Worker using System.Runtime.CompilerServices;
44*1b3f573fSAndroid Build Coastguard Worker #if !NET35
45*1b3f573fSAndroid Build Coastguard Worker using System.Threading.Tasks;
46*1b3f573fSAndroid Build Coastguard Worker #endif
47*1b3f573fSAndroid Build Coastguard Worker 
48*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf
49*1b3f573fSAndroid Build Coastguard Worker {
50*1b3f573fSAndroid Build Coastguard Worker     public class ByteStringTest
51*1b3f573fSAndroid Build Coastguard Worker     {
52*1b3f573fSAndroid Build Coastguard Worker         [Test]
Equality()53*1b3f573fSAndroid Build Coastguard Worker         public void Equality()
54*1b3f573fSAndroid Build Coastguard Worker         {
55*1b3f573fSAndroid Build Coastguard Worker             ByteString b1 = ByteString.CopyFrom(1, 2, 3);
56*1b3f573fSAndroid Build Coastguard Worker             ByteString b2 = ByteString.CopyFrom(1, 2, 3);
57*1b3f573fSAndroid Build Coastguard Worker             ByteString b3 = ByteString.CopyFrom(1, 2, 4);
58*1b3f573fSAndroid Build Coastguard Worker             ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4);
59*1b3f573fSAndroid Build Coastguard Worker             EqualityTester.AssertEquality(b1, b1);
60*1b3f573fSAndroid Build Coastguard Worker             EqualityTester.AssertEquality(b1, b2);
61*1b3f573fSAndroid Build Coastguard Worker             EqualityTester.AssertInequality(b1, b3);
62*1b3f573fSAndroid Build Coastguard Worker             EqualityTester.AssertInequality(b1, b4);
63*1b3f573fSAndroid Build Coastguard Worker             EqualityTester.AssertInequality(b1, null);
64*1b3f573fSAndroid Build Coastguard Worker             EqualityTester.AssertEquality(ByteString.Empty, ByteString.Empty);
65*1b3f573fSAndroid Build Coastguard Worker #pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1)
66*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(b1 == b1);
67*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(b1 == b2);
68*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse(b1 == b3);
69*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse(b1 == b4);
70*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse(b1 == null);
71*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue((ByteString) null == null);
72*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse(b1 != b1);
73*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse(b1 != b2);
74*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(ByteString.Empty == ByteString.Empty);
75*1b3f573fSAndroid Build Coastguard Worker #pragma warning disable 1718
76*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(b1 != b3);
77*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(b1 != b4);
78*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(b1 != null);
79*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse((ByteString) null != null);
80*1b3f573fSAndroid Build Coastguard Worker         }
81*1b3f573fSAndroid Build Coastguard Worker 
82*1b3f573fSAndroid Build Coastguard Worker         [Test]
EmptyByteStringHasZeroSize()83*1b3f573fSAndroid Build Coastguard Worker         public void EmptyByteStringHasZeroSize()
84*1b3f573fSAndroid Build Coastguard Worker         {
85*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, ByteString.Empty.Length);
86*1b3f573fSAndroid Build Coastguard Worker         }
87*1b3f573fSAndroid Build Coastguard Worker 
88*1b3f573fSAndroid Build Coastguard Worker         [Test]
CopyFromStringWithExplicitEncoding()89*1b3f573fSAndroid Build Coastguard Worker         public void CopyFromStringWithExplicitEncoding()
90*1b3f573fSAndroid Build Coastguard Worker         {
91*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom("AB", Encoding.Unicode);
92*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(4, bs.Length);
93*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(65, bs[0]);
94*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, bs[1]);
95*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(66, bs[2]);
96*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, bs[3]);
97*1b3f573fSAndroid Build Coastguard Worker         }
98*1b3f573fSAndroid Build Coastguard Worker 
99*1b3f573fSAndroid Build Coastguard Worker         [Test]
IsEmptyWhenEmpty()100*1b3f573fSAndroid Build Coastguard Worker         public void IsEmptyWhenEmpty()
101*1b3f573fSAndroid Build Coastguard Worker         {
102*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(ByteString.CopyFromUtf8("").IsEmpty);
103*1b3f573fSAndroid Build Coastguard Worker         }
104*1b3f573fSAndroid Build Coastguard Worker 
105*1b3f573fSAndroid Build Coastguard Worker         [Test]
IsEmptyWhenNotEmpty()106*1b3f573fSAndroid Build Coastguard Worker         public void IsEmptyWhenNotEmpty()
107*1b3f573fSAndroid Build Coastguard Worker         {
108*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse(ByteString.CopyFromUtf8("X").IsEmpty);
109*1b3f573fSAndroid Build Coastguard Worker         }
110*1b3f573fSAndroid Build Coastguard Worker 
111*1b3f573fSAndroid Build Coastguard Worker         [Test]
CopyFromByteArrayCopiesContents()112*1b3f573fSAndroid Build Coastguard Worker         public void CopyFromByteArrayCopiesContents()
113*1b3f573fSAndroid Build Coastguard Worker         {
114*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[1];
115*1b3f573fSAndroid Build Coastguard Worker             data[0] = 10;
116*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom(data);
117*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(10, bs[0]);
118*1b3f573fSAndroid Build Coastguard Worker             data[0] = 5;
119*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(10, bs[0]);
120*1b3f573fSAndroid Build Coastguard Worker         }
121*1b3f573fSAndroid Build Coastguard Worker 
122*1b3f573fSAndroid Build Coastguard Worker         [Test]
CopyFromReadOnlySpanCopiesContents()123*1b3f573fSAndroid Build Coastguard Worker         public void CopyFromReadOnlySpanCopiesContents()
124*1b3f573fSAndroid Build Coastguard Worker         {
125*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[1];
126*1b3f573fSAndroid Build Coastguard Worker             data[0] = 10;
127*1b3f573fSAndroid Build Coastguard Worker             ReadOnlySpan<byte> byteSpan = data;
128*1b3f573fSAndroid Build Coastguard Worker             var bs = ByteString.CopyFrom(byteSpan);
129*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(10, bs[0]);
130*1b3f573fSAndroid Build Coastguard Worker             data[0] = 5;
131*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(10, bs[0]);
132*1b3f573fSAndroid Build Coastguard Worker         }
133*1b3f573fSAndroid Build Coastguard Worker 
134*1b3f573fSAndroid Build Coastguard Worker         [Test]
ToByteArrayCopiesContents()135*1b3f573fSAndroid Build Coastguard Worker         public void ToByteArrayCopiesContents()
136*1b3f573fSAndroid Build Coastguard Worker         {
137*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFromUtf8("Hello");
138*1b3f573fSAndroid Build Coastguard Worker             byte[] data = bs.ToByteArray();
139*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual((byte)'H', data[0]);
140*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual((byte)'H', bs[0]);
141*1b3f573fSAndroid Build Coastguard Worker             data[0] = 0;
142*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, data[0]);
143*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual((byte)'H', bs[0]);
144*1b3f573fSAndroid Build Coastguard Worker         }
145*1b3f573fSAndroid Build Coastguard Worker 
146*1b3f573fSAndroid Build Coastguard Worker         [Test]
CopyFromUtf8UsesUtf8()147*1b3f573fSAndroid Build Coastguard Worker         public void CopyFromUtf8UsesUtf8()
148*1b3f573fSAndroid Build Coastguard Worker         {
149*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFromUtf8("\u20ac");
150*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, bs.Length);
151*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0xe2, bs[0]);
152*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0x82, bs[1]);
153*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0xac, bs[2]);
154*1b3f573fSAndroid Build Coastguard Worker         }
155*1b3f573fSAndroid Build Coastguard Worker 
156*1b3f573fSAndroid Build Coastguard Worker         [Test]
CopyFromPortion()157*1b3f573fSAndroid Build Coastguard Worker         public void CopyFromPortion()
158*1b3f573fSAndroid Build Coastguard Worker         {
159*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6};
160*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom(data, 2, 3);
161*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, bs.Length);
162*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2, bs[0]);
163*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, bs[1]);
164*1b3f573fSAndroid Build Coastguard Worker         }
165*1b3f573fSAndroid Build Coastguard Worker 
166*1b3f573fSAndroid Build Coastguard Worker         [Test]
CopyTo()167*1b3f573fSAndroid Build Coastguard Worker         public void CopyTo()
168*1b3f573fSAndroid Build Coastguard Worker         {
169*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 };
170*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom(data);
171*1b3f573fSAndroid Build Coastguard Worker 
172*1b3f573fSAndroid Build Coastguard Worker             byte[] dest = new byte[data.Length];
173*1b3f573fSAndroid Build Coastguard Worker             bs.CopyTo(dest, 0);
174*1b3f573fSAndroid Build Coastguard Worker 
175*1b3f573fSAndroid Build Coastguard Worker             CollectionAssert.AreEqual(data, dest);
176*1b3f573fSAndroid Build Coastguard Worker         }
177*1b3f573fSAndroid Build Coastguard Worker 
178*1b3f573fSAndroid Build Coastguard Worker         [Test]
GetEnumerator()179*1b3f573fSAndroid Build Coastguard Worker         public void GetEnumerator()
180*1b3f573fSAndroid Build Coastguard Worker         {
181*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 };
182*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom(data);
183*1b3f573fSAndroid Build Coastguard Worker 
184*1b3f573fSAndroid Build Coastguard Worker             IEnumerator<byte> genericEnumerator = bs.GetEnumerator();
185*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(genericEnumerator.MoveNext());
186*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, genericEnumerator.Current);
187*1b3f573fSAndroid Build Coastguard Worker 
188*1b3f573fSAndroid Build Coastguard Worker             IEnumerator enumerator = ((IEnumerable)bs).GetEnumerator();
189*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(enumerator.MoveNext());
190*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, enumerator.Current);
191*1b3f573fSAndroid Build Coastguard Worker 
192*1b3f573fSAndroid Build Coastguard Worker             // Call via LINQ
193*1b3f573fSAndroid Build Coastguard Worker             CollectionAssert.AreEqual(bs.Span.ToArray(), bs.ToArray());
194*1b3f573fSAndroid Build Coastguard Worker         }
195*1b3f573fSAndroid Build Coastguard Worker 
196*1b3f573fSAndroid Build Coastguard Worker         [Test]
UnsafeWrap()197*1b3f573fSAndroid Build Coastguard Worker         public void UnsafeWrap()
198*1b3f573fSAndroid Build Coastguard Worker         {
199*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 };
200*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = UnsafeByteOperations.UnsafeWrap(data.AsMemory(2, 3));
201*1b3f573fSAndroid Build Coastguard Worker             ReadOnlySpan<byte> s = bs.Span;
202*1b3f573fSAndroid Build Coastguard Worker 
203*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, s.Length);
204*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2, s[0]);
205*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, s[1]);
206*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(4, s[2]);
207*1b3f573fSAndroid Build Coastguard Worker 
208*1b3f573fSAndroid Build Coastguard Worker             // Check that the value is not a copy
209*1b3f573fSAndroid Build Coastguard Worker             data[2] = byte.MaxValue;
210*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(byte.MaxValue, s[0]);
211*1b3f573fSAndroid Build Coastguard Worker         }
212*1b3f573fSAndroid Build Coastguard Worker 
213*1b3f573fSAndroid Build Coastguard Worker         [Test]
CreateCodedInput_FromArraySegment()214*1b3f573fSAndroid Build Coastguard Worker         public void CreateCodedInput_FromArraySegment()
215*1b3f573fSAndroid Build Coastguard Worker         {
216*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 };
217*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = UnsafeByteOperations.UnsafeWrap(data.AsMemory(2, 3));
218*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream codedInputStream = bs.CreateCodedInput();
219*1b3f573fSAndroid Build Coastguard Worker 
220*1b3f573fSAndroid Build Coastguard Worker             byte[] bytes = codedInputStream.ReadRawBytes(3);
221*1b3f573fSAndroid Build Coastguard Worker 
222*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, bytes.Length);
223*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2, bytes[0]);
224*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, bytes[1]);
225*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(4, bytes[2]);
226*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(codedInputStream.IsAtEnd);
227*1b3f573fSAndroid Build Coastguard Worker         }
228*1b3f573fSAndroid Build Coastguard Worker 
229*1b3f573fSAndroid Build Coastguard Worker         [Test]
WriteToStream()230*1b3f573fSAndroid Build Coastguard Worker         public void WriteToStream()
231*1b3f573fSAndroid Build Coastguard Worker         {
232*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 };
233*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom(data);
234*1b3f573fSAndroid Build Coastguard Worker 
235*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
236*1b3f573fSAndroid Build Coastguard Worker             bs.WriteTo(ms);
237*1b3f573fSAndroid Build Coastguard Worker 
238*1b3f573fSAndroid Build Coastguard Worker             CollectionAssert.AreEqual(data, ms.ToArray());
239*1b3f573fSAndroid Build Coastguard Worker         }
240*1b3f573fSAndroid Build Coastguard Worker 
241*1b3f573fSAndroid Build Coastguard Worker         [Test]
WriteToStream_Stackalloc()242*1b3f573fSAndroid Build Coastguard Worker         public void WriteToStream_Stackalloc()
243*1b3f573fSAndroid Build Coastguard Worker         {
244*1b3f573fSAndroid Build Coastguard Worker             byte[] data = Encoding.UTF8.GetBytes("Hello world");
245*1b3f573fSAndroid Build Coastguard Worker             Span<byte> s = stackalloc byte[data.Length];
246*1b3f573fSAndroid Build Coastguard Worker             data.CopyTo(s);
247*1b3f573fSAndroid Build Coastguard Worker 
248*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
249*1b3f573fSAndroid Build Coastguard Worker 
250*1b3f573fSAndroid Build Coastguard Worker             using (UnmanagedMemoryManager<byte> manager = new UnmanagedMemoryManager<byte>(s))
251*1b3f573fSAndroid Build Coastguard Worker             {
252*1b3f573fSAndroid Build Coastguard Worker                 ByteString bs = ByteString.AttachBytes(manager.Memory);
253*1b3f573fSAndroid Build Coastguard Worker 
254*1b3f573fSAndroid Build Coastguard Worker                 bs.WriteTo(ms);
255*1b3f573fSAndroid Build Coastguard Worker             }
256*1b3f573fSAndroid Build Coastguard Worker 
257*1b3f573fSAndroid Build Coastguard Worker             CollectionAssert.AreEqual(data, ms.ToArray());
258*1b3f573fSAndroid Build Coastguard Worker         }
259*1b3f573fSAndroid Build Coastguard Worker 
260*1b3f573fSAndroid Build Coastguard Worker         [Test]
ToStringUtf8()261*1b3f573fSAndroid Build Coastguard Worker         public void ToStringUtf8()
262*1b3f573fSAndroid Build Coastguard Worker         {
263*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFromUtf8("\u20ac");
264*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual("\u20ac", bs.ToStringUtf8());
265*1b3f573fSAndroid Build Coastguard Worker         }
266*1b3f573fSAndroid Build Coastguard Worker 
267*1b3f573fSAndroid Build Coastguard Worker         [Test]
ToStringWithExplicitEncoding()268*1b3f573fSAndroid Build Coastguard Worker         public void ToStringWithExplicitEncoding()
269*1b3f573fSAndroid Build Coastguard Worker         {
270*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode);
271*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode));
272*1b3f573fSAndroid Build Coastguard Worker         }
273*1b3f573fSAndroid Build Coastguard Worker 
274*1b3f573fSAndroid Build Coastguard Worker         [Test]
ToString_Stackalloc()275*1b3f573fSAndroid Build Coastguard Worker         public void ToString_Stackalloc()
276*1b3f573fSAndroid Build Coastguard Worker         {
277*1b3f573fSAndroid Build Coastguard Worker             byte[] data = Encoding.UTF8.GetBytes("Hello world");
278*1b3f573fSAndroid Build Coastguard Worker             Span<byte> s = stackalloc byte[data.Length];
279*1b3f573fSAndroid Build Coastguard Worker             data.CopyTo(s);
280*1b3f573fSAndroid Build Coastguard Worker 
281*1b3f573fSAndroid Build Coastguard Worker             using (UnmanagedMemoryManager<byte> manager = new UnmanagedMemoryManager<byte>(s))
282*1b3f573fSAndroid Build Coastguard Worker             {
283*1b3f573fSAndroid Build Coastguard Worker                 ByteString bs = ByteString.AttachBytes(manager.Memory);
284*1b3f573fSAndroid Build Coastguard Worker 
285*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual("Hello world", bs.ToString(Encoding.UTF8));
286*1b3f573fSAndroid Build Coastguard Worker             }
287*1b3f573fSAndroid Build Coastguard Worker         }
288*1b3f573fSAndroid Build Coastguard Worker 
289*1b3f573fSAndroid Build Coastguard Worker         [Test]
FromBase64_WithText()290*1b3f573fSAndroid Build Coastguard Worker         public void FromBase64_WithText()
291*1b3f573fSAndroid Build Coastguard Worker         {
292*1b3f573fSAndroid Build Coastguard Worker             byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6};
293*1b3f573fSAndroid Build Coastguard Worker             string base64 = Convert.ToBase64String(data);
294*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.FromBase64(base64);
295*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(data, bs.ToByteArray());
296*1b3f573fSAndroid Build Coastguard Worker         }
297*1b3f573fSAndroid Build Coastguard Worker 
298*1b3f573fSAndroid Build Coastguard Worker         [Test]
FromBase64_Empty()299*1b3f573fSAndroid Build Coastguard Worker         public void FromBase64_Empty()
300*1b3f573fSAndroid Build Coastguard Worker         {
301*1b3f573fSAndroid Build Coastguard Worker             // Optimization which also fixes issue 61.
302*1b3f573fSAndroid Build Coastguard Worker             Assert.AreSame(ByteString.Empty, ByteString.FromBase64(""));
303*1b3f573fSAndroid Build Coastguard Worker         }
304*1b3f573fSAndroid Build Coastguard Worker 
305*1b3f573fSAndroid Build Coastguard Worker         [Test]
ToBase64_Array()306*1b3f573fSAndroid Build Coastguard Worker         public void ToBase64_Array()
307*1b3f573fSAndroid Build Coastguard Worker         {
308*1b3f573fSAndroid Build Coastguard Worker             ByteString bs = ByteString.CopyFrom(Encoding.UTF8.GetBytes("Hello world"));
309*1b3f573fSAndroid Build Coastguard Worker 
310*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64());
311*1b3f573fSAndroid Build Coastguard Worker         }
312*1b3f573fSAndroid Build Coastguard Worker 
313*1b3f573fSAndroid Build Coastguard Worker         [Test]
ToBase64_Stackalloc()314*1b3f573fSAndroid Build Coastguard Worker         public void ToBase64_Stackalloc()
315*1b3f573fSAndroid Build Coastguard Worker         {
316*1b3f573fSAndroid Build Coastguard Worker             byte[] data = Encoding.UTF8.GetBytes("Hello world");
317*1b3f573fSAndroid Build Coastguard Worker             Span<byte> s = stackalloc byte[data.Length];
318*1b3f573fSAndroid Build Coastguard Worker             data.CopyTo(s);
319*1b3f573fSAndroid Build Coastguard Worker 
320*1b3f573fSAndroid Build Coastguard Worker             using (UnmanagedMemoryManager<byte> manager = new UnmanagedMemoryManager<byte>(s))
321*1b3f573fSAndroid Build Coastguard Worker             {
322*1b3f573fSAndroid Build Coastguard Worker                 ByteString bs = ByteString.AttachBytes(manager.Memory);
323*1b3f573fSAndroid Build Coastguard Worker 
324*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64());
325*1b3f573fSAndroid Build Coastguard Worker             }
326*1b3f573fSAndroid Build Coastguard Worker         }
327*1b3f573fSAndroid Build Coastguard Worker 
328*1b3f573fSAndroid Build Coastguard Worker         [Test]
FromStream_Seekable()329*1b3f573fSAndroid Build Coastguard Worker         public void FromStream_Seekable()
330*1b3f573fSAndroid Build Coastguard Worker         {
331*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
332*1b3f573fSAndroid Build Coastguard Worker             // Consume the first byte, just to test that it's "from current position"
333*1b3f573fSAndroid Build Coastguard Worker             stream.ReadByte();
334*1b3f573fSAndroid Build Coastguard Worker             var actual = ByteString.FromStream(stream);
335*1b3f573fSAndroid Build Coastguard Worker             ByteString expected = ByteString.CopyFrom(2, 3, 4, 5);
336*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
337*1b3f573fSAndroid Build Coastguard Worker         }
338*1b3f573fSAndroid Build Coastguard Worker 
339*1b3f573fSAndroid Build Coastguard Worker         [Test]
FromStream_NotSeekable()340*1b3f573fSAndroid Build Coastguard Worker         public void FromStream_NotSeekable()
341*1b3f573fSAndroid Build Coastguard Worker         {
342*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
343*1b3f573fSAndroid Build Coastguard Worker             // Consume the first byte, just to test that it's "from current position"
344*1b3f573fSAndroid Build Coastguard Worker             stream.ReadByte();
345*1b3f573fSAndroid Build Coastguard Worker             // Wrap the original stream in LimitedInputStream, which has CanSeek=false
346*1b3f573fSAndroid Build Coastguard Worker             var limitedStream = new LimitedInputStream(stream, 3);
347*1b3f573fSAndroid Build Coastguard Worker             var actual = ByteString.FromStream(limitedStream);
348*1b3f573fSAndroid Build Coastguard Worker             ByteString expected = ByteString.CopyFrom(2, 3, 4);
349*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
350*1b3f573fSAndroid Build Coastguard Worker         }
351*1b3f573fSAndroid Build Coastguard Worker 
352*1b3f573fSAndroid Build Coastguard Worker #if !NET35
353*1b3f573fSAndroid Build Coastguard Worker         [Test]
FromStreamAsync_Seekable()354*1b3f573fSAndroid Build Coastguard Worker         public async Task FromStreamAsync_Seekable()
355*1b3f573fSAndroid Build Coastguard Worker         {
356*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
357*1b3f573fSAndroid Build Coastguard Worker             // Consume the first byte, just to test that it's "from current position"
358*1b3f573fSAndroid Build Coastguard Worker             stream.ReadByte();
359*1b3f573fSAndroid Build Coastguard Worker             var actual = await ByteString.FromStreamAsync(stream);
360*1b3f573fSAndroid Build Coastguard Worker             ByteString expected = ByteString.CopyFrom(2, 3, 4, 5);
361*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
362*1b3f573fSAndroid Build Coastguard Worker         }
363*1b3f573fSAndroid Build Coastguard Worker 
364*1b3f573fSAndroid Build Coastguard Worker         [Test]
FromStreamAsync_NotSeekable()365*1b3f573fSAndroid Build Coastguard Worker         public async Task FromStreamAsync_NotSeekable()
366*1b3f573fSAndroid Build Coastguard Worker         {
367*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
368*1b3f573fSAndroid Build Coastguard Worker             // Consume the first byte, just to test that it's "from current position"
369*1b3f573fSAndroid Build Coastguard Worker             stream.ReadByte();
370*1b3f573fSAndroid Build Coastguard Worker             // Wrap the original stream in LimitedInputStream, which has CanSeek=false
371*1b3f573fSAndroid Build Coastguard Worker             var limitedStream = new LimitedInputStream(stream, 3);
372*1b3f573fSAndroid Build Coastguard Worker             var actual = await ByteString.FromStreamAsync(limitedStream);
373*1b3f573fSAndroid Build Coastguard Worker             ByteString expected = ByteString.CopyFrom(2, 3, 4);
374*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
375*1b3f573fSAndroid Build Coastguard Worker         }
376*1b3f573fSAndroid Build Coastguard Worker #endif
377*1b3f573fSAndroid Build Coastguard Worker 
378*1b3f573fSAndroid Build Coastguard Worker         [Test]
GetHashCode_Regression()379*1b3f573fSAndroid Build Coastguard Worker         public void GetHashCode_Regression()
380*1b3f573fSAndroid Build Coastguard Worker         {
381*1b3f573fSAndroid Build Coastguard Worker             // We used to have an awful hash algorithm where only the last four
382*1b3f573fSAndroid Build Coastguard Worker             // bytes were relevant. This is a regression test for
383*1b3f573fSAndroid Build Coastguard Worker             // https://github.com/protocolbuffers/protobuf/issues/2511
384*1b3f573fSAndroid Build Coastguard Worker 
385*1b3f573fSAndroid Build Coastguard Worker             ByteString b1 = ByteString.CopyFrom(100, 1, 2, 3, 4);
386*1b3f573fSAndroid Build Coastguard Worker             ByteString b2 = ByteString.CopyFrom(200, 1, 2, 3, 4);
387*1b3f573fSAndroid Build Coastguard Worker             Assert.AreNotEqual(b1.GetHashCode(), b2.GetHashCode());
388*1b3f573fSAndroid Build Coastguard Worker         }
389*1b3f573fSAndroid Build Coastguard Worker 
390*1b3f573fSAndroid Build Coastguard Worker         [Test]
GetContentsAsReadOnlySpan()391*1b3f573fSAndroid Build Coastguard Worker         public void GetContentsAsReadOnlySpan()
392*1b3f573fSAndroid Build Coastguard Worker         {
393*1b3f573fSAndroid Build Coastguard Worker             var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5);
394*1b3f573fSAndroid Build Coastguard Worker             var copied = byteString.Span.ToArray();
395*1b3f573fSAndroid Build Coastguard Worker             CollectionAssert.AreEqual(byteString, copied);
396*1b3f573fSAndroid Build Coastguard Worker         }
397*1b3f573fSAndroid Build Coastguard Worker 
398*1b3f573fSAndroid Build Coastguard Worker         [Test]
GetContentsAsReadOnlyMemory()399*1b3f573fSAndroid Build Coastguard Worker         public void GetContentsAsReadOnlyMemory()
400*1b3f573fSAndroid Build Coastguard Worker         {
401*1b3f573fSAndroid Build Coastguard Worker             var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5);
402*1b3f573fSAndroid Build Coastguard Worker             var copied = byteString.Memory.ToArray();
403*1b3f573fSAndroid Build Coastguard Worker             CollectionAssert.AreEqual(byteString, copied);
404*1b3f573fSAndroid Build Coastguard Worker         }
405*1b3f573fSAndroid Build Coastguard Worker 
406*1b3f573fSAndroid Build Coastguard Worker         // Create Memory<byte> from non-array source.
407*1b3f573fSAndroid Build Coastguard Worker         // Use by ByteString tests that have optimized path for array backed Memory<byte>.
408*1b3f573fSAndroid Build Coastguard Worker         private sealed unsafe class UnmanagedMemoryManager<T> : MemoryManager<T> where T : unmanaged
409*1b3f573fSAndroid Build Coastguard Worker         {
410*1b3f573fSAndroid Build Coastguard Worker             private readonly T* _pointer;
411*1b3f573fSAndroid Build Coastguard Worker             private readonly int _length;
412*1b3f573fSAndroid Build Coastguard Worker 
UnmanagedMemoryManager(Span<T> span)413*1b3f573fSAndroid Build Coastguard Worker             public UnmanagedMemoryManager(Span<T> span)
414*1b3f573fSAndroid Build Coastguard Worker             {
415*1b3f573fSAndroid Build Coastguard Worker                 fixed (T* ptr = &MemoryMarshal.GetReference(span))
416*1b3f573fSAndroid Build Coastguard Worker                 {
417*1b3f573fSAndroid Build Coastguard Worker                     _pointer = ptr;
418*1b3f573fSAndroid Build Coastguard Worker                     _length = span.Length;
419*1b3f573fSAndroid Build Coastguard Worker                 }
420*1b3f573fSAndroid Build Coastguard Worker             }
421*1b3f573fSAndroid Build Coastguard Worker 
GetSpan()422*1b3f573fSAndroid Build Coastguard Worker             public override Span<T> GetSpan() => new Span<T>(_pointer, _length);
423*1b3f573fSAndroid Build Coastguard Worker 
Pin(int elementIndex = 0)424*1b3f573fSAndroid Build Coastguard Worker             public override MemoryHandle Pin(int elementIndex = 0)
425*1b3f573fSAndroid Build Coastguard Worker             {
426*1b3f573fSAndroid Build Coastguard Worker                 if (elementIndex < 0 || elementIndex >= _length)
427*1b3f573fSAndroid Build Coastguard Worker                 {
428*1b3f573fSAndroid Build Coastguard Worker                     throw new ArgumentOutOfRangeException(nameof(elementIndex));
429*1b3f573fSAndroid Build Coastguard Worker                 }
430*1b3f573fSAndroid Build Coastguard Worker 
431*1b3f573fSAndroid Build Coastguard Worker                 return new MemoryHandle(_pointer + elementIndex);
432*1b3f573fSAndroid Build Coastguard Worker             }
433*1b3f573fSAndroid Build Coastguard Worker 
Unpin()434*1b3f573fSAndroid Build Coastguard Worker             public override void Unpin() { }
435*1b3f573fSAndroid Build Coastguard Worker 
Dispose(bool disposing)436*1b3f573fSAndroid Build Coastguard Worker             protected override void Dispose(bool disposing) { }
437*1b3f573fSAndroid Build Coastguard Worker         }
438*1b3f573fSAndroid Build Coastguard Worker     }
439*1b3f573fSAndroid Build Coastguard Worker }