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 }