1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2008 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 33 using System; 34 using System.Text; 35 using NUnit.Framework; 36 using System.IO; 37 #if !NET35 38 using System.Threading.Tasks; 39 #endif 40 41 namespace Google.Protobuf 42 { 43 public class ByteStringTest 44 { 45 [Test] Equality()46 public void Equality() 47 { 48 ByteString b1 = ByteString.CopyFrom(1, 2, 3); 49 ByteString b2 = ByteString.CopyFrom(1, 2, 3); 50 ByteString b3 = ByteString.CopyFrom(1, 2, 4); 51 ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4); 52 EqualityTester.AssertEquality(b1, b1); 53 EqualityTester.AssertEquality(b1, b2); 54 EqualityTester.AssertInequality(b1, b3); 55 EqualityTester.AssertInequality(b1, b4); 56 EqualityTester.AssertInequality(b1, null); 57 #pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1) 58 Assert.IsTrue(b1 == b1); 59 Assert.IsTrue(b1 == b2); 60 Assert.IsFalse(b1 == b3); 61 Assert.IsFalse(b1 == b4); 62 Assert.IsFalse(b1 == null); 63 Assert.IsTrue((ByteString) null == null); 64 Assert.IsFalse(b1 != b1); 65 Assert.IsFalse(b1 != b2); 66 #pragma warning disable 1718 67 Assert.IsTrue(b1 != b3); 68 Assert.IsTrue(b1 != b4); 69 Assert.IsTrue(b1 != null); 70 Assert.IsFalse((ByteString) null != null); 71 } 72 73 [Test] EmptyByteStringHasZeroSize()74 public void EmptyByteStringHasZeroSize() 75 { 76 Assert.AreEqual(0, ByteString.Empty.Length); 77 } 78 79 [Test] CopyFromStringWithExplicitEncoding()80 public void CopyFromStringWithExplicitEncoding() 81 { 82 ByteString bs = ByteString.CopyFrom("AB", Encoding.Unicode); 83 Assert.AreEqual(4, bs.Length); 84 Assert.AreEqual(65, bs[0]); 85 Assert.AreEqual(0, bs[1]); 86 Assert.AreEqual(66, bs[2]); 87 Assert.AreEqual(0, bs[3]); 88 } 89 90 [Test] IsEmptyWhenEmpty()91 public void IsEmptyWhenEmpty() 92 { 93 Assert.IsTrue(ByteString.CopyFromUtf8("").IsEmpty); 94 } 95 96 [Test] IsEmptyWhenNotEmpty()97 public void IsEmptyWhenNotEmpty() 98 { 99 Assert.IsFalse(ByteString.CopyFromUtf8("X").IsEmpty); 100 } 101 102 [Test] CopyFromByteArrayCopiesContents()103 public void CopyFromByteArrayCopiesContents() 104 { 105 byte[] data = new byte[1]; 106 data[0] = 10; 107 ByteString bs = ByteString.CopyFrom(data); 108 Assert.AreEqual(10, bs[0]); 109 data[0] = 5; 110 Assert.AreEqual(10, bs[0]); 111 } 112 113 [Test] CopyFromReadOnlySpanCopiesContents()114 public void CopyFromReadOnlySpanCopiesContents() 115 { 116 byte[] data = new byte[1]; 117 data[0] = 10; 118 ReadOnlySpan<byte> byteSpan = data; 119 var bs = ByteString.CopyFrom(byteSpan); 120 Assert.AreEqual(10, bs[0]); 121 data[0] = 5; 122 Assert.AreEqual(10, bs[0]); 123 } 124 125 [Test] ToByteArrayCopiesContents()126 public void ToByteArrayCopiesContents() 127 { 128 ByteString bs = ByteString.CopyFromUtf8("Hello"); 129 byte[] data = bs.ToByteArray(); 130 Assert.AreEqual((byte)'H', data[0]); 131 Assert.AreEqual((byte)'H', bs[0]); 132 data[0] = 0; 133 Assert.AreEqual(0, data[0]); 134 Assert.AreEqual((byte)'H', bs[0]); 135 } 136 137 [Test] CopyFromUtf8UsesUtf8()138 public void CopyFromUtf8UsesUtf8() 139 { 140 ByteString bs = ByteString.CopyFromUtf8("\u20ac"); 141 Assert.AreEqual(3, bs.Length); 142 Assert.AreEqual(0xe2, bs[0]); 143 Assert.AreEqual(0x82, bs[1]); 144 Assert.AreEqual(0xac, bs[2]); 145 } 146 147 [Test] CopyFromPortion()148 public void CopyFromPortion() 149 { 150 byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; 151 ByteString bs = ByteString.CopyFrom(data, 2, 3); 152 Assert.AreEqual(3, bs.Length); 153 Assert.AreEqual(2, bs[0]); 154 Assert.AreEqual(3, bs[1]); 155 } 156 157 [Test] ToStringUtf8()158 public void ToStringUtf8() 159 { 160 ByteString bs = ByteString.CopyFromUtf8("\u20ac"); 161 Assert.AreEqual("\u20ac", bs.ToStringUtf8()); 162 } 163 164 [Test] ToStringWithExplicitEncoding()165 public void ToStringWithExplicitEncoding() 166 { 167 ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode); 168 Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode)); 169 } 170 171 [Test] FromBase64_WithText()172 public void FromBase64_WithText() 173 { 174 byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; 175 string base64 = Convert.ToBase64String(data); 176 ByteString bs = ByteString.FromBase64(base64); 177 Assert.AreEqual(data, bs.ToByteArray()); 178 } 179 180 [Test] FromBase64_Empty()181 public void FromBase64_Empty() 182 { 183 // Optimization which also fixes issue 61. 184 Assert.AreSame(ByteString.Empty, ByteString.FromBase64("")); 185 } 186 187 [Test] FromStream_Seekable()188 public void FromStream_Seekable() 189 { 190 var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); 191 // Consume the first byte, just to test that it's "from current position" 192 stream.ReadByte(); 193 var actual = ByteString.FromStream(stream); 194 ByteString expected = ByteString.CopyFrom(2, 3, 4, 5); 195 Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); 196 } 197 198 [Test] FromStream_NotSeekable()199 public void FromStream_NotSeekable() 200 { 201 var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); 202 // Consume the first byte, just to test that it's "from current position" 203 stream.ReadByte(); 204 // Wrap the original stream in LimitedInputStream, which has CanSeek=false 205 var limitedStream = new LimitedInputStream(stream, 3); 206 var actual = ByteString.FromStream(limitedStream); 207 ByteString expected = ByteString.CopyFrom(2, 3, 4); 208 Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); 209 } 210 211 #if !NET35 212 [Test] FromStreamAsync_Seekable()213 public async Task FromStreamAsync_Seekable() 214 { 215 var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); 216 // Consume the first byte, just to test that it's "from current position" 217 stream.ReadByte(); 218 var actual = await ByteString.FromStreamAsync(stream); 219 ByteString expected = ByteString.CopyFrom(2, 3, 4, 5); 220 Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); 221 } 222 223 [Test] FromStreamAsync_NotSeekable()224 public async Task FromStreamAsync_NotSeekable() 225 { 226 var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); 227 // Consume the first byte, just to test that it's "from current position" 228 stream.ReadByte(); 229 // Wrap the original stream in LimitedInputStream, which has CanSeek=false 230 var limitedStream = new LimitedInputStream(stream, 3); 231 var actual = await ByteString.FromStreamAsync(limitedStream); 232 ByteString expected = ByteString.CopyFrom(2, 3, 4); 233 Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); 234 } 235 #endif 236 237 [Test] GetHashCode_Regression()238 public void GetHashCode_Regression() 239 { 240 // We used to have an awful hash algorithm where only the last four 241 // bytes were relevant. This is a regression test for 242 // https://github.com/protocolbuffers/protobuf/issues/2511 243 244 ByteString b1 = ByteString.CopyFrom(100, 1, 2, 3, 4); 245 ByteString b2 = ByteString.CopyFrom(200, 1, 2, 3, 4); 246 Assert.AreNotEqual(b1.GetHashCode(), b2.GetHashCode()); 247 } 248 249 [Test] GetContentsAsReadOnlySpan()250 public void GetContentsAsReadOnlySpan() 251 { 252 var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5); 253 var copied = byteString.Span.ToArray(); 254 CollectionAssert.AreEqual(byteString, copied); 255 } 256 257 [Test] GetContentsAsReadOnlyMemory()258 public void GetContentsAsReadOnlyMemory() 259 { 260 var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5); 261 var copied = byteString.Memory.ToArray(); 262 CollectionAssert.AreEqual(byteString, copied); 263 } 264 } 265 }