// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CommunityToolkit.HighPerformance.UnitTests.Extensions; [TestClass] public class Test_StreamExtensions { [TestMethod] public void Test_StreamExtensions_ReadWrite() { // bool (1), int (4), float (4), long (8) = 17 bytes. // Leave two extra bytes for the partial read (fail). Stream stream = new byte[19].AsMemory().AsStream(); stream.Write(true); stream.Write(42); stream.Write(3.14f); stream.Write(unchecked(uint.MaxValue * 324823489204ul)); Assert.AreEqual(17, stream.Position); _ = Assert.ThrowsExactly(() => stream.Write(long.MaxValue)); stream.Position = 0; Assert.IsTrue(stream.Read()); Assert.AreEqual(42, stream.Read()); Assert.AreEqual(3.14f, stream.Read()); Assert.AreEqual(unchecked(uint.MaxValue * 324823489204ul), stream.Read()); _ = Assert.ThrowsExactly(() => stream.Read()); } // See https://github.com/CommunityToolkit/dotnet/issues/513 [TestMethod] public void Test_StreamExtensions_ReadWrite_WithBufferedStream() { Stream stream = new BufferedStream(); stream.Write(true); stream.Write(42); stream.Write(3.14f); stream.Write(unchecked(uint.MaxValue * 324823489204ul)); stream.Position = 0; Assert.IsTrue(stream.Read()); Assert.AreEqual(42, stream.Read()); Assert.AreEqual(3.14f, stream.Read()); Assert.AreEqual(unchecked(uint.MaxValue * 324823489204ul), stream.Read()); _ = Assert.ThrowsExactly(() => stream.Read()); } private sealed class BufferedStream : MemoryStream { private ReadOnlyMemory bufferedBytes; public override int Read(byte[] buffer, int offset, int count) { if (this.bufferedBytes.IsEmpty) { this.bufferedBytes = ReadMoreBytes(); } int bytesToCopy = Math.Min(this.bufferedBytes.Length, count); this.bufferedBytes.Span.Slice(0, bytesToCopy).CopyTo(buffer.AsSpan(offset, count)); this.bufferedBytes = this.bufferedBytes.Slice(bytesToCopy); return bytesToCopy; } #if NET6_0_OR_GREATER public override int Read(Span buffer) { if (this.bufferedBytes.IsEmpty) { this.bufferedBytes = ReadMoreBytes(); } int bytesToCopy = Math.Min(this.bufferedBytes.Length, buffer.Length); this.bufferedBytes.Span.Slice(0, bytesToCopy).CopyTo(buffer); this.bufferedBytes = this.bufferedBytes.Slice(bytesToCopy); return bytesToCopy; } #endif private byte[] ReadMoreBytes() { byte[] array = new byte[3]; int bytesOffset = 0; do { int bytesRead = base.Read(array, bytesOffset, 3 - bytesOffset); bytesOffset += bytesRead; if (bytesRead == 0) { return array.AsSpan(0, bytesOffset).ToArray(); } } while (bytesOffset < 3); return array; } } }