From 1468a3b854362ba850a1fcbb8595f862adef43cd Mon Sep 17 00:00:00 2001 From: mizady <90141999+mizady@users.noreply.github.com> Date: Mon, 23 Dec 2024 14:46:39 -0500 Subject: [PATCH 1/2] Fix MemoryStream.CanWrite to allow read-only Add _isWritable backing CanWrite so that stream can be made read only via another constructor that specifies whether the stream is writable. Add Test for new constructor in CanWrite tests --- System.IO.Streams/MemoryStream.cs | 41 +++++++++++++++++++-- UnitTests/MemoryStreamUnitTests/CanWrite.cs | 14 +++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/System.IO.Streams/MemoryStream.cs b/System.IO.Streams/MemoryStream.cs index 3715c71..38da76b 100644 --- a/System.IO.Streams/MemoryStream.cs +++ b/System.IO.Streams/MemoryStream.cs @@ -27,6 +27,8 @@ public class MemoryStream : Stream private readonly bool _expandable; // Is this stream open or closed? private bool _isOpen; + // Is the stream writable + private bool _isWritable; private const int MemStreamMaxLength = 0xFFFF; @@ -50,6 +52,7 @@ public MemoryStream() // Must be 0 for byte[]'s created by MemoryStream _origin = 0; _isOpen = true; + _isWritable = true; } /// @@ -61,9 +64,6 @@ public MemoryStream() /// /// The , , and properties are all set to . /// - /// - /// The capacity of the current stream automatically increases when you use the method to set the length to a value larger than the capacity of the current stream. - /// /// public MemoryStream(byte[] buffer) { @@ -73,6 +73,24 @@ public MemoryStream(byte[] buffer) _expandable = false; _origin = 0; _isOpen = true; + _isWritable = true; + } + + /// + /// Initializes a new non-resizable instance of the class based on the specified byte array with the property set as specified. + /// + /// The array of unsigned bytes from which to create the current stream. + /// A bool indicating whether the stream should be writable + /// is . + public MemoryStream(byte[] buffer, bool isWritable) + { + _buffer = buffer ?? throw new ArgumentNullException(); + + _length = _capacity = buffer.Length; + _expandable = false; + _origin = 0; + _isOpen = true; + _isWritable = isWritable; } /// @@ -115,7 +133,7 @@ public MemoryStream(byte[] buffer) /// If the stream is closed, this property returns . /// /// - public override bool CanWrite => _isOpen; + public override bool CanWrite => _isWritable; /// protected override void Dispose(bool disposing) @@ -335,6 +353,11 @@ public override void SetLength(long value) { EnsureOpen(); + if(!CanWrite) + { + throw new NotSupportedException(); + } + if (value > MemStreamMaxLength || value < 0) { throw new ArgumentOutOfRangeException(); @@ -377,6 +400,11 @@ public override void Write(byte[] buffer, int offset, int count) { EnsureOpen(); + if (!CanWrite) + { + throw new NotSupportedException(); + } + if (buffer == null) { throw new ArgumentNullException(); @@ -417,6 +445,11 @@ public override void WriteByte(byte value) { EnsureOpen(); + if (!CanWrite) + { + throw new NotSupportedException(); + } + if (_position >= _capacity) { EnsureCapacity(_position + 1); diff --git a/UnitTests/MemoryStreamUnitTests/CanWrite.cs b/UnitTests/MemoryStreamUnitTests/CanWrite.cs index 18add87..5f6e0b7 100644 --- a/UnitTests/MemoryStreamUnitTests/CanWrite.cs +++ b/UnitTests/MemoryStreamUnitTests/CanWrite.cs @@ -51,5 +51,19 @@ public void CanWrite_Byte_Ctor() OutputHelper.WriteLine($"Unexpected exception {ex}"); } } + + [TestMethod] + public void CanWrite_bool_false_Ctor() + { + // Arrange + byte[] buffer = new byte[1024]; + + // Act + using MemoryStream fs = new MemoryStream(buffer, false); + + // Assert + Assert.IsFalse(fs.CanWrite, "Expected CanWrite == false, but got CanWrite == true"); + Assert.ThrowsException(typeof(NotSupportedException), () => fs.WriteByte(0), "Expected exception when attempt to write to a read only stream."); + } } } From 911ce0f5b978b17cb8f3f20f4095d199137f3158 Mon Sep 17 00:00:00 2001 From: mizady <90141999+mizady@users.noreply.github.com> Date: Tue, 24 Dec 2024 12:48:00 -0500 Subject: [PATCH 2/2] Refactored to reduce repetition Modified test for new constructor to include both true and false conditions. Combined constructors to reduce repetition. Moved CanWrite check to private function to reduce repetition. --- System.IO.Streams/MemoryStream.cs | 41 ++++++++------------- UnitTests/MemoryStreamUnitTests/CanWrite.cs | 13 +++++-- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/System.IO.Streams/MemoryStream.cs b/System.IO.Streams/MemoryStream.cs index 38da76b..a96f7a9 100644 --- a/System.IO.Streams/MemoryStream.cs +++ b/System.IO.Streams/MemoryStream.cs @@ -65,16 +65,7 @@ public MemoryStream() /// The , , and properties are all set to . /// /// - public MemoryStream(byte[] buffer) - { - _buffer = buffer ?? throw new ArgumentNullException(); - - _length = _capacity = buffer.Length; - _expandable = false; - _origin = 0; - _isOpen = true; - _isWritable = true; - } + public MemoryStream(byte[] buffer) : this(buffer, true) { } /// /// Initializes a new non-resizable instance of the class based on the specified byte array with the property set as specified. @@ -352,11 +343,7 @@ public override long Seek( public override void SetLength(long value) { EnsureOpen(); - - if(!CanWrite) - { - throw new NotSupportedException(); - } + EnsureWritable(); if (value > MemStreamMaxLength || value < 0) { @@ -399,11 +386,7 @@ public virtual byte[] ToArray() public override void Write(byte[] buffer, int offset, int count) { EnsureOpen(); - - if (!CanWrite) - { - throw new NotSupportedException(); - } + EnsureWritable(); if (buffer == null) { @@ -444,11 +427,7 @@ public override void Write(byte[] buffer, int offset, int count) public override void WriteByte(byte value) { EnsureOpen(); - - if (!CanWrite) - { - throw new NotSupportedException(); - } + EnsureWritable(); if (_position >= _capacity) { @@ -492,6 +471,18 @@ private void EnsureOpen() } } + /// + /// Check that stream is writable + /// + /// + private void EnsureWritable() + { + if (!CanWrite) + { + throw new NotSupportedException(); + } + } + /// /// Verifies that there is enough capacity in the stream. /// diff --git a/UnitTests/MemoryStreamUnitTests/CanWrite.cs b/UnitTests/MemoryStreamUnitTests/CanWrite.cs index 5f6e0b7..a26d29c 100644 --- a/UnitTests/MemoryStreamUnitTests/CanWrite.cs +++ b/UnitTests/MemoryStreamUnitTests/CanWrite.cs @@ -53,17 +53,22 @@ public void CanWrite_Byte_Ctor() } [TestMethod] - public void CanWrite_bool_false_Ctor() + [DataRow(true)] + [DataRow(false)] + public void CanWrite_bool_isWritable_Ctor(bool isWritable) { // Arrange byte[] buffer = new byte[1024]; // Act - using MemoryStream fs = new MemoryStream(buffer, false); + using MemoryStream fs = new MemoryStream(buffer, isWritable); // Assert - Assert.IsFalse(fs.CanWrite, "Expected CanWrite == false, but got CanWrite == true"); - Assert.ThrowsException(typeof(NotSupportedException), () => fs.WriteByte(0), "Expected exception when attempt to write to a read only stream."); + Assert.AreEqual(isWritable, fs.CanWrite, $"Expected CanWrite == {isWritable}, but got CanWrite == {!isWritable}"); + if(!isWritable) + { + Assert.ThrowsException(typeof(NotSupportedException), () => fs.WriteByte(0), "Expected exception when attempt to write to a read only stream."); + } } } }