Moved all unit test files into a separate directory in preparation for splitting the project

This commit is contained in:
Markus Ewald 2024-07-24 13:27:29 +02:00 committed by cygon
parent 28b96fd557
commit ba5234f701
58 changed files with 0 additions and 853 deletions

View file

@ -1,561 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using System.IO;
using NUnit.Framework;
namespace Nuclex.Support.IO {
/// <summary>Unit Test for the stream chainer</summary>
[TestFixture]
internal class ChainStreamTest {
#region class TestStream
/// <summary>Testing stream that allows specific features to be disabled</summary>
private class TestStream : Stream {
/// <summary>Initializes a new test stream</summary>
/// <param name="wrappedStream">Stream that will be wrapped</param>
/// <param name="allowRead">Whether to allow reading from the stream</param>
/// <param name="allowWrite">Whether to allow writing to the stream</param>
/// <param name="allowSeek">Whether to allow seeking within the stream</param>
public TestStream(
Stream wrappedStream, bool allowRead, bool allowWrite, bool allowSeek
) {
this.stream = wrappedStream;
this.readAllowed = allowRead;
this.writeAllowed = allowWrite;
this.seekAllowed = allowSeek;
}
/// <summary>Whether data can be read from the stream</summary>
public override bool CanRead {
get { return this.readAllowed; }
}
/// <summary>Whether the stream supports seeking</summary>
public override bool CanSeek {
get { return this.seekAllowed; }
}
/// <summary>Whether data can be written into the stream</summary>
public override bool CanWrite {
get { return this.writeAllowed; }
}
/// <summary>
/// Clears all buffers for this stream and causes any buffered data to be written
/// to the underlying device.
/// </summary>
public override void Flush() {
++this.flushCallCount;
this.stream.Flush();
}
/// <summary>Length of the stream in bytes</summary>
public override long Length {
get {
enforceSeekAllowed();
return this.stream.Length;
}
}
/// <summary>Absolute position of the file pointer within the stream</summary>
/// <exception cref="NotSupportedException">
/// At least one of the chained streams does not support seeking
/// </exception>
public override long Position {
get {
enforceSeekAllowed();
return this.stream.Position;
}
set {
enforceSeekAllowed();
this.stream.Position = value;
}
}
/// <summary>
/// Reads a sequence of bytes from the stream and advances the position of
/// the file pointer by the number of bytes read.
/// </summary>
/// <param name="buffer">Buffer that will receive the data read from the stream</param>
/// <param name="offset">
/// Offset in the buffer at which the stream will place the data read
/// </param>
/// <param name="count">Maximum number of bytes that will be read</param>
/// <returns>
/// The number of bytes that were actually read from the stream and written into
/// the provided buffer
/// </returns>
public override int Read(byte[] buffer, int offset, int count) {
enforceReadAllowed();
return this.stream.Read(buffer, offset, count);
}
/// <summary>Changes the position of the file pointer</summary>
/// <param name="offset">
/// Offset to move the file pointer by, relative to the position indicated by
/// the <paramref name="origin" /> parameter.
/// </param>
/// <param name="origin">
/// Reference point relative to which the file pointer is placed
/// </param>
/// <returns>The new absolute position within the stream</returns>
public override long Seek(long offset, SeekOrigin origin) {
enforceSeekAllowed();
return this.stream.Seek(offset, origin);
}
/// <summary>Changes the length of the stream</summary>
/// <param name="value">New length the stream shall have</param>
public override void SetLength(long value) {
enforceSeekAllowed();
this.stream.SetLength(value);
}
/// <summary>
/// Writes a sequence of bytes to the stream and advances the position of
/// the file pointer by the number of bytes written.
/// </summary>
/// <param name="buffer">
/// Buffer containing the data that will be written to the stream
/// </param>
/// <param name="offset">
/// Offset in the buffer at which the data to be written starts
/// </param>
/// <param name="count">Number of bytes that will be written into the stream</param>
public override void Write(byte[] buffer, int offset, int count) {
enforceWriteAllowed();
this.stream.Write(buffer, offset, count);
}
/// <summary>Number of times the Flush() method has been called</summary>
public int FlushCallCount {
get { return this.flushCallCount; }
}
/// <summary>Throws an exception if reading is not allowed</summary>
private void enforceReadAllowed() {
if(!this.readAllowed) {
throw new NotSupportedException("Reading has been disabled");
}
}
/// <summary>Throws an exception if writing is not allowed</summary>
private void enforceWriteAllowed() {
if(!this.writeAllowed) {
throw new NotSupportedException("Writing has been disabled");
}
}
/// <summary>Throws an exception if seeking is not allowed</summary>
private void enforceSeekAllowed() {
if(!this.seekAllowed) {
throw new NotSupportedException("Seeking has been disabled");
}
}
/// <summary>Stream being wrapped for testing</summary>
private Stream stream;
/// <summary>whether to allow reading from the wrapped stream</summary>
private bool readAllowed;
/// <summary>Whether to allow writing to the wrapped stream</summary>
private bool writeAllowed;
/// <summary>Whether to allow seeking within the wrapped stream</summary>
private bool seekAllowed;
/// <summary>Number of times the Flush() method has been called</summary>
private int flushCallCount;
}
#endregion // class TestStream
/// <summary>
/// Tests whether the stream chainer correctly partitions a long write request
/// over its chained streams and appends any remaining data to the end of
/// the last chained stream.
/// </summary>
[Test]
public void TestPartitionedWrite() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
byte[] testData = new byte[20];
for(int index = 0; index < testData.Length; ++index) {
testData[index] = (byte)(index + 1);
}
chainer.Position = 5;
chainer.Write(testData, 0, testData.Length);
Assert.AreEqual(
new byte[] { 0, 0, 0, 0, 0, 1, 2, 3, 4, 5 },
((MemoryStream)chainer.ChainedStreams[0]).ToArray()
);
Assert.AreEqual(
new byte[] { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 },
((MemoryStream)chainer.ChainedStreams[1]).ToArray()
);
}
/// <summary>
/// Tests whether the stream chainer correctly partitions a long read request
/// over its chained streams.
/// </summary>
[Test]
public void TestPartitionedRead() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
((MemoryStream)chainer.ChainedStreams[0]).Write(
new byte[] { 1, 2, 3, 4, 5 }, 0, 5
);
((MemoryStream)chainer.ChainedStreams[1]).Write(
new byte[] { 6, 7, 8, 9, 10 }, 0, 5
);
chainer.Position = 3;
byte[] buffer = new byte[15];
int bytesRead = chainer.Read(buffer, 0, 14);
Assert.AreEqual(14, bytesRead);
Assert.AreEqual(new byte[] { 4, 5, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 0, 0, 0 }, buffer);
}
/// <summary>
/// Tests whether the stream chainer can handle a stream resize
/// </summary>
[Test]
public void TestWriteAfterResize() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
// The first stream has a size of 10 bytes, so this goes into the second stream
chainer.Position = 11;
chainer.Write(new byte[] { 12, 34 }, 0, 2);
// Now we resize the first stream to 15 bytes, so this goes into the first stream
((MemoryStream)chainer.ChainedStreams[0]).SetLength(15);
chainer.Write(new byte[] { 56, 78, 11, 22 }, 0, 4);
Assert.AreEqual(
new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 78 },
((MemoryStream)chainer.ChainedStreams[0]).ToArray()
);
Assert.AreEqual(
new byte[] { 11, 22, 34, 0, 0, 0, 0, 0, 0, 0 },
((MemoryStream)chainer.ChainedStreams[1]).ToArray()
);
}
/// <summary>
/// Tests writing to a stream chainer that contains an unseekable stream
/// </summary>
[Test]
public void TestWriteToUnseekableStream() {
MemoryStream firstStream = new MemoryStream();
// Now the second stream _does_ support seeking. If the stream chainer ignores
// that, it would overwrite data in the second stream.
MemoryStream secondStream = new MemoryStream();
secondStream.Write(new byte[] { 0, 9, 8, 7, 6 }, 0, 5);
secondStream.Position = 0;
TestStream testStream = new TestStream(firstStream, true, true, false);
ChainStream chainer = new ChainStream(new Stream[] { testStream, secondStream });
chainer.Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
Assert.IsFalse(chainer.CanSeek);
Assert.AreEqual(0, firstStream.Length);
Assert.AreEqual(new byte[] { 0, 9, 8, 7, 6, 1, 2, 3, 4, 5 }, secondStream.ToArray());
}
/// <summary>
/// Tests reading from a stream chainer that contains an unseekable stream
/// </summary>
[Test]
public void TestReadFromUnseekableStream() {
MemoryStream firstStream = new MemoryStream();
// Now the second stream _does_ support seeking. If the stream chainer ignores
// that, it would overwrite data in the second stream.
MemoryStream secondStream = new MemoryStream();
secondStream.Write(new byte[] { 0, 9, 8, 7, 6 }, 0, 5);
secondStream.Position = 3;
TestStream testStream = new TestStream(firstStream, true, true, false);
ChainStream chainer = new ChainStream(new Stream[] { testStream, secondStream });
Assert.IsFalse(chainer.CanSeek);
byte[] buffer = new byte[5];
int readByteCount = chainer.Read(buffer, 0, 3);
Assert.AreEqual(3, readByteCount);
Assert.AreEqual(new byte[] { 0, 9, 8, 0, 0 }, buffer);
readByteCount = chainer.Read(buffer, 0, 3);
Assert.AreEqual(2, readByteCount);
Assert.AreEqual(new byte[] { 7, 6, 8, 0, 0 }, buffer);
}
/// <summary>
/// Tests reading from a stream chainer that contains an unreadable stream
/// </summary>
[Test]
public void TestThrowOnReadFromUnreadableStream() {
MemoryStream memoryStream = new MemoryStream();
TestStream testStream = new TestStream(memoryStream, false, true, true);
ChainStream chainer = new ChainStream(new Stream[] { testStream });
Assert.Throws<NotSupportedException>(
delegate() { chainer.Read(new byte[5], 0, 5); }
);
}
/// <summary>
/// Tests writing to a stream chainer that contains an unwriteable stream
/// </summary>
[Test]
public void TestThrowOnWriteToUnwriteableStream() {
MemoryStream memoryStream = new MemoryStream();
TestStream testStream = new TestStream(memoryStream, true, false, true);
ChainStream chainer = new ChainStream(new Stream[] { testStream });
Assert.Throws<NotSupportedException>(
delegate() { chainer.Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5); }
);
}
/// <summary>
/// Verifies that the stream chainer throws an exception if the attempt is
/// made to change the length of the stream
/// </summary>
[Test]
public void TestThrowOnLengthChange() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
Assert.Throws<NotSupportedException>(
delegate() { chainer.SetLength(123); }
);
}
/// <summary>
/// Verifies that the CanRead property is correctly determined by the stream chainer
/// </summary>
[Test]
public void TestCanRead() {
MemoryStream yesStream = new MemoryStream();
TestStream noStream = new TestStream(yesStream, false, true, true);
Stream[] yesGroup = new Stream[] { yesStream, yesStream, yesStream, yesStream };
Stream[] partialGroup = new Stream[] { yesStream, yesStream, noStream, yesStream };
Stream[] noGroup = new Stream[] { noStream, noStream, noStream, noStream };
Assert.IsTrue(new ChainStream(yesGroup).CanRead);
Assert.IsFalse(new ChainStream(partialGroup).CanRead);
Assert.IsFalse(new ChainStream(noGroup).CanRead);
}
/// <summary>
/// Verifies that the CanRead property is correctly determined by the stream chainer
/// </summary>
[Test]
public void TestCanWrite() {
MemoryStream yesStream = new MemoryStream();
TestStream noStream = new TestStream(yesStream, true, false, true);
Stream[] yesGroup = new Stream[] { yesStream, yesStream, yesStream, yesStream };
Stream[] partialGroup = new Stream[] { yesStream, yesStream, noStream, yesStream };
Stream[] noGroup = new Stream[] { noStream, noStream, noStream, noStream };
Assert.IsTrue(new ChainStream(yesGroup).CanWrite);
Assert.IsFalse(new ChainStream(partialGroup).CanWrite);
Assert.IsFalse(new ChainStream(noGroup).CanWrite);
}
/// <summary>
/// Verifies that the CanSeek property is correctly determined by the stream chainer
/// </summary>
[Test]
public void TestCanSeek() {
MemoryStream yesStream = new MemoryStream();
TestStream noStream = new TestStream(yesStream, true, true, false);
Stream[] yesGroup = new Stream[] { yesStream, yesStream, yesStream, yesStream };
Stream[] partialGroup = new Stream[] { yesStream, yesStream, noStream, yesStream };
Stream[] noGroup = new Stream[] { noStream, noStream, noStream, noStream };
Assert.IsTrue(new ChainStream(yesGroup).CanSeek);
Assert.IsFalse(new ChainStream(partialGroup).CanSeek);
Assert.IsFalse(new ChainStream(noGroup).CanSeek);
}
/// <summary>
/// Tests whether an exception is thrown if the Seek() method is called on
/// a stream chainer with streams that do not support seeking
/// </summary>
[Test]
public void TestThrowOnSeekWithUnseekableStream() {
MemoryStream memoryStream = new MemoryStream();
TestStream testStream = new TestStream(memoryStream, true, true, false);
ChainStream chainer = new ChainStream(new Stream[] { testStream });
Assert.Throws<NotSupportedException>(
delegate() { chainer.Seek(123, SeekOrigin.Begin); }
);
}
/// <summary>
/// Tests whether an exception is thrown if the Position property is retrieved
/// on a stream chainer with streams that do not support seeking
/// </summary>
[Test]
public void TestThrowOnGetPositionWithUnseekableStream() {
MemoryStream memoryStream = new MemoryStream();
TestStream testStream = new TestStream(memoryStream, true, true, false);
ChainStream chainer = new ChainStream(new Stream[] { testStream });
Assert.Throws<NotSupportedException>(
delegate() { Console.WriteLine(chainer.Position); }
);
}
/// <summary>
/// Tests whether an exception is thrown if the Position property is set
/// on a stream chainer with streams that do not support seeking
/// </summary>
[Test]
public void TestThrowOnSetPositionWithUnseekableStream() {
MemoryStream memoryStream = new MemoryStream();
TestStream testStream = new TestStream(memoryStream, true, true, false);
ChainStream chainer = new ChainStream(new Stream[] { testStream });
Assert.Throws<NotSupportedException>(
delegate() { chainer.Position = 123; }
);
}
/// <summary>
/// Tests whether an exception is thrown if the Length property is retrieved
/// on a stream chainer with streams that do not support seeking
/// </summary>
[Test]
public void TestThrowOnGetLengthWithUnseekableStream() {
MemoryStream memoryStream = new MemoryStream();
TestStream testStream = new TestStream(memoryStream, true, true, false);
ChainStream chainer = new ChainStream(new Stream[] { testStream });
Assert.Throws<NotSupportedException>(
delegate() { Assert.IsTrue(chainer.Length != chainer.Length); }
);
}
/// <summary>
/// Tests whether the Seek() method of the stream chainer is working
/// </summary>
[Test]
public void TestSeeking() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
Assert.AreEqual(7, chainer.Seek(-13, SeekOrigin.End));
Assert.AreEqual(14, chainer.Seek(7, SeekOrigin.Current));
Assert.AreEqual(11, chainer.Seek(11, SeekOrigin.Begin));
}
/// <summary>
/// Tests whether the stream behaves correctly if data is read from beyond its end
/// </summary>
[Test]
public void TestReadBeyondEndOfStream() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
chainer.Seek(10, SeekOrigin.End);
// This is how the MemoryStream behaves: it returns 0 bytes.
int readByteCount = chainer.Read(new byte[1], 0, 1);
Assert.AreEqual(0, readByteCount);
}
/// <summary>
/// Tests whether the Seek() method throws an exception if an invalid
/// reference point is provided
/// </summary>
[Test]
public void TestThrowOnInvalidSeekReferencePoint() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
Assert.Throws<ArgumentException>(
delegate() { chainer.Seek(1, (SeekOrigin)12345); }
);
}
/// <summary>Verifies that the position property works correctly</summary>
[Test]
public void TestPositionChange() {
ChainStream chainer = chainTwoStreamsOfTenBytes();
chainer.Position = 7;
Assert.AreEqual(chainer.Position, 7);
chainer.Position = 14;
Assert.AreEqual(chainer.Position, 14);
}
/// <summary>Tests the Flush() method of the stream chainer</summary>
[Test]
public void TestFlush() {
MemoryStream firstStream = new MemoryStream();
TestStream firstTestStream = new TestStream(firstStream, true, true, true);
MemoryStream secondStream = new MemoryStream();
TestStream secondTestStream = new TestStream(secondStream, true, true, true);
ChainStream chainer = new ChainStream(
new Stream[] { firstTestStream, secondTestStream }
);
Assert.AreEqual(0, firstTestStream.FlushCallCount);
Assert.AreEqual(0, secondTestStream.FlushCallCount);
chainer.Flush();
Assert.AreEqual(1, firstTestStream.FlushCallCount);
Assert.AreEqual(1, secondTestStream.FlushCallCount);
}
/// <summary>
/// Creates a stream chainer with two streams that each have a size of 10 bytes
/// </summary>
/// <returns>The new stream chainer with two chained 10-byte streams</returns>
private static ChainStream chainTwoStreamsOfTenBytes() {
MemoryStream firstStream = new MemoryStream(10);
MemoryStream secondStream = new MemoryStream(10);
firstStream.SetLength(10);
secondStream.SetLength(10);
return new ChainStream(
new Stream[] { firstStream, secondStream }
);
}
}
} // namespace Nuclex.Support.IO
#endif // UNITTEST

View file

@ -1,526 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using System.IO;
using NUnit.Framework;
namespace Nuclex.Support.IO {
/// <summary>Unit Test for the partial stream</summary>
[TestFixture]
internal class PartialStreamTest {
#region class TestStream
/// <summary>Testing stream that allows specific features to be disabled</summary>
private class TestStream : Stream {
/// <summary>Initializes a new test stream</summary>
/// <param name="wrappedStream">Stream that will be wrapped</param>
/// <param name="allowRead">Whether to allow reading from the stream</param>
/// <param name="allowWrite">Whether to allow writing to the stream</param>
/// <param name="allowSeek">Whether to allow seeking within the stream</param>
public TestStream(
Stream wrappedStream, bool allowRead, bool allowWrite, bool allowSeek
) {
this.stream = wrappedStream;
this.readAllowed = allowRead;
this.writeAllowed = allowWrite;
this.seekAllowed = allowSeek;
}
/// <summary>Whether data can be read from the stream</summary>
public override bool CanRead {
get { return this.readAllowed; }
}
/// <summary>Whether the stream supports seeking</summary>
public override bool CanSeek {
get { return this.seekAllowed; }
}
/// <summary>Whether data can be written into the stream</summary>
public override bool CanWrite {
get { return this.writeAllowed; }
}
/// <summary>
/// Clears all buffers for this stream and causes any buffered data to be written
/// to the underlying device.
/// </summary>
public override void Flush() {
++this.flushCallCount;
this.stream.Flush();
}
/// <summary>Length of the stream in bytes</summary>
public override long Length {
get {
enforceSeekAllowed();
return this.stream.Length;
}
}
/// <summary>Absolute position of the file pointer within the stream</summary>
/// <exception cref="NotSupportedException">
/// At least one of the chained streams does not support seeking
/// </exception>
public override long Position {
get {
enforceSeekAllowed();
return this.stream.Position;
}
set {
enforceSeekAllowed();
this.stream.Position = value;
}
}
/// <summary>
/// Reads a sequence of bytes from the stream and advances the position of
/// the file pointer by the number of bytes read.
/// </summary>
/// <param name="buffer">Buffer that will receive the data read from the stream</param>
/// <param name="offset">
/// Offset in the buffer at which the stream will place the data read
/// </param>
/// <param name="count">Maximum number of bytes that will be read</param>
/// <returns>
/// The number of bytes that were actually read from the stream and written into
/// the provided buffer
/// </returns>
public override int Read(byte[] buffer, int offset, int count) {
enforceReadAllowed();
return this.stream.Read(buffer, offset, count);
}
/// <summary>Changes the position of the file pointer</summary>
/// <param name="offset">
/// Offset to move the file pointer by, relative to the position indicated by
/// the <paramref name="origin" /> parameter.
/// </param>
/// <param name="origin">
/// Reference point relative to which the file pointer is placed
/// </param>
/// <returns>The new absolute position within the stream</returns>
public override long Seek(long offset, SeekOrigin origin) {
enforceSeekAllowed();
return this.stream.Seek(offset, origin);
}
/// <summary>Changes the length of the stream</summary>
/// <param name="value">New length the stream shall have</param>
public override void SetLength(long value) {
enforceSeekAllowed();
this.stream.SetLength(value);
}
/// <summary>
/// Writes a sequence of bytes to the stream and advances the position of
/// the file pointer by the number of bytes written.
/// </summary>
/// <param name="buffer">
/// Buffer containing the data that will be written to the stream
/// </param>
/// <param name="offset">
/// Offset in the buffer at which the data to be written starts
/// </param>
/// <param name="count">Number of bytes that will be written into the stream</param>
public override void Write(byte[] buffer, int offset, int count) {
enforceWriteAllowed();
this.stream.Write(buffer, offset, count);
}
/// <summary>Number of times the Flush() method has been called</summary>
public int FlushCallCount {
get { return this.flushCallCount; }
}
/// <summary>Throws an exception if reading is not allowed</summary>
private void enforceReadAllowed() {
if(!this.readAllowed) {
throw new NotSupportedException("Reading has been disabled");
}
}
/// <summary>Throws an exception if writing is not allowed</summary>
private void enforceWriteAllowed() {
if(!this.writeAllowed) {
throw new NotSupportedException("Writing has been disabled");
}
}
/// <summary>Throws an exception if seeking is not allowed</summary>
private void enforceSeekAllowed() {
if(!this.seekAllowed) {
throw new NotSupportedException("Seeking has been disabled");
}
}
/// <summary>Stream being wrapped for testing</summary>
private Stream stream;
/// <summary>whether to allow reading from the wrapped stream</summary>
private bool readAllowed;
/// <summary>Whether to allow writing to the wrapped stream</summary>
private bool writeAllowed;
/// <summary>Whether to allow seeking within the wrapped stream</summary>
private bool seekAllowed;
/// <summary>Number of times the Flush() method has been called</summary>
private int flushCallCount;
}
#endregion // class TestStream
/// <summary>Tests whether the partial stream constructor is working</summary>
[Test]
public void TestConstructor() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
PartialStream partialStream = new PartialStream(memoryStream, 23, 100);
Assert.AreEqual(100, partialStream.Length);
}
}
/// <summary>
/// Verifies that the partial stream constructor throws an exception if
/// it's invoked with an invalid start offset
/// </summary>
[Test]
public void TestThrowOnInvalidStartInConstructor() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
Assert.Throws<ArgumentException>(
delegate() { Console.WriteLine(new PartialStream(memoryStream, -1, 10)); }
);
}
}
/// <summary>
/// Verifies that the partial stream constructor throws an exception if
/// it's invoked with an invalid start offset
/// </summary>
[Test]
public void TestThrowOnInvalidLengthInConstructor() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
Assert.Throws<ArgumentException>(
delegate() { Console.WriteLine(new PartialStream(memoryStream, 100, 24)); }
);
}
}
/// <summary>
/// Verifies that the partial stream constructor throws an exception if
/// it's invoked with a start offset on an unseekable stream
/// </summary>
[Test]
public void TestThrowOnUnseekableStreamWithOffsetInConstructor() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
TestStream testStream = new TestStream(memoryStream, true, true, false);
Assert.Throws<ArgumentException>(
delegate() { Console.WriteLine(new PartialStream(testStream, 23, 100)); }
);
}
}
/// <summary>
/// Tests whether the CanRead property reports its status correctly
/// </summary>
[Test]
public void TestCanReadProperty() {
using(MemoryStream memoryStream = new MemoryStream()) {
TestStream yesStream = new TestStream(memoryStream, true, true, true);
TestStream noStream = new TestStream(memoryStream, false, true, true);
Assert.IsTrue(new PartialStream(yesStream, 0, 0).CanRead);
Assert.IsFalse(new PartialStream(noStream, 0, 0).CanRead);
}
}
/// <summary>
/// Tests whether the CanWrite property reports its status correctly
/// </summary>
[Test]
public void TestCanWriteProperty() {
using(MemoryStream memoryStream = new MemoryStream()) {
TestStream yesStream = new TestStream(memoryStream, true, true, true);
TestStream noStream = new TestStream(memoryStream, true, false, true);
Assert.IsTrue(new PartialStream(yesStream, 0, 0).CanWrite);
Assert.IsFalse(new PartialStream(noStream, 0, 0).CanWrite);
}
}
/// <summary>
/// Tests whether the CanSeek property reports its status correctly
/// </summary>
[Test]
public void TestCanSeekProperty() {
using(MemoryStream memoryStream = new MemoryStream()) {
TestStream yesStream = new TestStream(memoryStream, true, true, true);
TestStream noStream = new TestStream(memoryStream, true, true, false);
Assert.IsTrue(new PartialStream(yesStream, 0, 0).CanSeek);
Assert.IsFalse(new PartialStream(noStream, 0, 0).CanSeek);
}
}
/// <summary>
/// Tests whether the CompleteStream property returns the original stream
/// </summary>
[Test]
public void TestCompleteStreamProperty() {
using(MemoryStream memoryStream = new MemoryStream()) {
PartialStream partialStream = new PartialStream(memoryStream, 0, 0);
Assert.AreSame(memoryStream, partialStream.CompleteStream);
}
}
/// <summary>Tests whether the Flush() method can be called</summary>
[Test]
public void TestFlush() {
using(MemoryStream memoryStream = new MemoryStream()) {
PartialStream partialStream = new PartialStream(memoryStream, 0, 0);
partialStream.Flush();
}
}
/// <summary>
/// Tests whether the Position property correctly reports the file pointer position
/// </summary>
[Test]
public void TestGetPosition() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
PartialStream partialStream = new PartialStream(memoryStream, 23, 100);
Assert.AreEqual(0, partialStream.Position);
byte[] test = new byte[10];
int bytesRead = partialStream.Read(test, 0, 10);
Assert.AreEqual(10, bytesRead);
Assert.AreEqual(10, partialStream.Position);
bytesRead = partialStream.Read(test, 0, 10);
Assert.AreEqual(10, bytesRead);
Assert.AreEqual(20, partialStream.Position);
}
}
/// <summary>
/// Tests whether the Position property is correctly updated
/// </summary>
[Test]
public void TestSetPosition() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
PartialStream partialStream = new PartialStream(memoryStream, 23, 100);
Assert.AreEqual(0, partialStream.Position);
partialStream.Position = 7;
Assert.AreEqual(partialStream.Position, 7);
partialStream.Position = 14;
Assert.AreEqual(partialStream.Position, 14);
}
}
/// <summary>
/// Tests whether the Position property throws an exception if the stream does
/// not support seeking.
/// </summary>
[Test]
public void TestThrowOnGetPositionOnUnseekableStream() {
using(MemoryStream memoryStream = new MemoryStream()) {
TestStream testStream = new TestStream(memoryStream, true, true, false);
PartialStream partialStream = new PartialStream(testStream, 0, 0);
Assert.Throws<NotSupportedException>(
delegate() { Console.WriteLine(partialStream.Position); }
);
}
}
/// <summary>
/// Tests whether the Position property throws an exception if the stream does
/// not support seeking.
/// </summary>
[Test]
public void TestThrowOnSetPositionOnUnseekableStream() {
using(MemoryStream memoryStream = new MemoryStream()) {
TestStream testStream = new TestStream(memoryStream, true, true, false);
PartialStream partialStream = new PartialStream(testStream, 0, 0);
Assert.Throws<NotSupportedException>(
delegate() { partialStream.Position = 0; }
);
}
}
/// <summary>
/// Tests whether the Read() method throws an exception if the stream does
/// not support reading
/// </summary>
[Test]
public void TestThrowOnReadFromUnreadableStream() {
using(MemoryStream memoryStream = new MemoryStream()) {
TestStream testStream = new TestStream(memoryStream, false, true, true);
PartialStream partialStream = new PartialStream(testStream, 0, 0);
byte[] test = new byte[10];
Assert.Throws<NotSupportedException>(
delegate() { Console.WriteLine(partialStream.Read(test, 0, 10)); }
);
}
}
/// <summary>
/// Tests whether the Seek() method of the partial stream is working
/// </summary>
[Test]
public void TestSeeking() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(20);
PartialStream partialStream = new PartialStream(memoryStream, 0, 20);
Assert.AreEqual(7, partialStream.Seek(-13, SeekOrigin.End));
Assert.AreEqual(14, partialStream.Seek(7, SeekOrigin.Current));
Assert.AreEqual(11, partialStream.Seek(11, SeekOrigin.Begin));
}
}
/// <summary>
/// Tests whether the Seek() method throws an exception if an invalid
/// reference point is provided
/// </summary>
[Test]
public void TestThrowOnInvalidSeekReferencePoint() {
using(MemoryStream memoryStream = new MemoryStream()) {
PartialStream partialStream = new PartialStream(memoryStream, 0, 0);
Assert.Throws<ArgumentException>(
delegate() { partialStream.Seek(1, (SeekOrigin)12345); }
);
}
}
/// <summary>
/// Verifies that the partial stream throws an exception if the attempt is
/// made to change the length of the stream
/// </summary>
[Test]
public void TestThrowOnLengthChange() {
using(MemoryStream memoryStream = new MemoryStream()) {
PartialStream partialStream = new PartialStream(memoryStream, 0, 0);
Assert.Throws<NotSupportedException>(
delegate() { partialStream.SetLength(123); }
);
}
}
/// <summary>
/// Tests whether the Read() method returns 0 bytes if the attempt is made
/// to read data from an invalid position
/// </summary>
[Test]
public void TestReadFromInvalidPosition() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
memoryStream.Position = 1123;
byte[] test = new byte[10];
Assert.AreEqual(0, memoryStream.Read(test, 0, 10));
}
}
/// <summary>Verifies that the Read() method is working</summary>
[Test]
public void TestReadFromPartialStream() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
memoryStream.Position = 100;
memoryStream.Write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 0, 10);
PartialStream partialStream = new PartialStream(memoryStream, 95, 10);
byte[] buffer = new byte[15];
int bytesRead = partialStream.Read(buffer, 0, 15);
Assert.AreEqual(10, bytesRead);
Assert.AreEqual(
new byte[] { 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0 }, buffer
);
}
}
/// <summary>Verifies that the Write() method is working</summary>
[Test]
public void TestWriteToPartialStream() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(123);
memoryStream.Position = 60;
memoryStream.Write(new byte[] { 11, 12, 13, 14, 15 }, 0, 5);
PartialStream partialStream = new PartialStream(memoryStream, 50, 15);
partialStream.Position = 3;
partialStream.Write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 0, 10);
byte[] buffer = new byte[17];
memoryStream.Position = 49;
int bytesRead = memoryStream.Read(buffer, 0, 17);
Assert.AreEqual(17, bytesRead);
Assert.AreEqual(
new byte[] { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 0 },
buffer
);
}
}
/// <summary>
/// Verifies that an exception is thrown if the Write() method of the partial stream
/// is attempted to be used to extend the partial stream's length
/// </summary>
[Test]
public void TestThrowOnExtendPartialStream() {
using(MemoryStream memoryStream = new MemoryStream()) {
memoryStream.SetLength(25);
PartialStream partialStream = new PartialStream(memoryStream, 10, 10);
partialStream.Position = 5;
Assert.Throws<NotSupportedException>(
delegate() { partialStream.Write(new byte[] { 1, 2, 3, 4, 5, 6 }, 0, 6); }
);
}
}
}
} // namespace Nuclex.Support.IO
#endif // UNITTEST

View file

@ -1,329 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
using System;
using System.IO;
#if UNITTEST
using NUnit.Framework;
namespace Nuclex.Support.IO {
/// <summary>Unit Test for the ring buffer class</summary>
[TestFixture]
internal class RingMemoryStreamTest {
/// <summary>Prepares some test data for the units test methods</summary>
[TestFixtureSetUp]
public void Setup() {
this.testBytes = new byte[20];
for(int i = 0; i < 20; ++i)
this.testBytes[i] = (byte)i;
}
/// <summary>
/// Ensures that the ring buffer blocks write attempts that would exceed its capacity
/// </summary>
[Test]
public void TestWriteTooLargeChunk() {
Assert.Throws<OverflowException>(
delegate() { new RingMemoryStream(10).Write(this.testBytes, 0, 11); }
);
}
/// <summary>
/// Ensures that the ring buffer still accepts write attempts that would fill the
/// entire buffer in one go.
/// </summary>
[Test]
public void TestWriteBarelyFittingChunk() {
new RingMemoryStream(10).Write(this.testBytes, 0, 10);
}
/// <summary>
/// Ensures that the ring buffer correctly manages write attempts that have to
/// be split at the end of the ring buffer
/// </summary>
[Test]
public void TestWriteSplitBlock() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(this.testBytes, 0, 8);
testRing.Read(this.testBytes, 0, 5);
testRing.Write(this.testBytes, 0, 7);
byte[] actual = new byte[10];
testRing.Read(actual, 0, 10);
Assert.AreEqual(new byte[] { 5, 6, 7, 0, 1, 2, 3, 4, 5, 6 }, actual);
}
/// <summary>
/// Ensures that the ring buffer correctly manages write attempts that write into
/// the gap after the ring buffer's data has become split
/// </summary>
[Test]
public void TestWriteSplitAndLinearBlock() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(this.testBytes, 0, 8);
testRing.Read(this.testBytes, 0, 5);
testRing.Write(this.testBytes, 0, 5);
testRing.Write(this.testBytes, 0, 2);
byte[] actual = new byte[10];
testRing.Read(actual, 0, 10);
Assert.AreEqual(new byte[] { 5, 6, 7, 0, 1, 2, 3, 4, 0, 1 }, actual);
}
/// <summary>
/// Ensures that the ring buffer still detects write that would exceed its capacity
/// if they write into the gap after the ring buffer's data has become split
/// </summary>
[Test]
public void TestWriteSplitAndLinearTooLargeBlock() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(this.testBytes, 0, 8);
testRing.Read(this.testBytes, 0, 5);
testRing.Write(this.testBytes, 0, 5);
Assert.Throws<OverflowException>(
delegate() { testRing.Write(this.testBytes, 0, 3); }
);
}
/// <summary>Tests whether the ring buffer correctly handles fragmentation</summary>
[Test]
public void TestSplitBlockWrappedRead() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(this.testBytes, 0, 10);
testRing.Read(this.testBytes, 0, 5);
testRing.Write(this.testBytes, 0, 5);
byte[] actual = new byte[10];
testRing.Read(actual, 0, 10);
Assert.AreEqual(new byte[] { 5, 6, 7, 8, 9, 0, 1, 2, 3, 4 }, actual);
}
/// <summary>Tests whether the ring buffer correctly handles fragmentation</summary>
[Test]
public void TestSplitBlockLinearRead() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(this.testBytes, 0, 10);
testRing.Read(this.testBytes, 0, 5);
testRing.Write(this.testBytes, 0, 5);
byte[] actual = new byte[5];
testRing.Read(actual, 0, 5);
Assert.AreEqual(new byte[] { 5, 6, 7, 8, 9 }, actual);
}
/// <summary>
/// Tests whether the ring buffer correctly returns partial data if more
/// data is requested than is contained in it.
/// </summary>
[Test]
public void TestEndOfStream() {
byte[] tempBytes = new byte[10];
RingMemoryStream testRing = new RingMemoryStream(10);
Assert.AreEqual(0, testRing.Read(tempBytes, 0, 5));
testRing.Write(this.testBytes, 0, 5);
Assert.AreEqual(5, testRing.Read(tempBytes, 0, 10));
testRing.Write(this.testBytes, 0, 6);
testRing.Read(tempBytes, 0, 5);
testRing.Write(this.testBytes, 0, 9);
Assert.AreEqual(10, testRing.Read(tempBytes, 0, 20));
}
/// <summary>
/// Validates that the ring buffer can extend its capacity without loosing data
/// </summary>
[Test]
public void TestCapacityIncrease() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(this.testBytes, 0, 10);
testRing.Capacity = 20;
byte[] actual = new byte[10];
testRing.Read(actual, 0, 10);
Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, actual);
}
/// <summary>
/// Validates that the ring buffer can reduce its capacity without loosing data
/// </summary>
[Test]
public void TestCapacityDecrease() {
RingMemoryStream testRing = new RingMemoryStream(20);
testRing.Write(this.testBytes, 0, 10);
testRing.Capacity = 10;
byte[] actual = new byte[10];
testRing.Read(actual, 0, 10);
Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, actual);
}
/// <summary>
/// Checks that an exception is thrown when the ring buffer's capacity is
/// reduced so much it would have to give up some of its contained data
/// </summary>
[Test]
public void TestCapacityDecreaseException() {
RingMemoryStream testRing = new RingMemoryStream(20);
testRing.Write(this.testBytes, 0, 20);
Assert.Throws<ArgumentOutOfRangeException>(
delegate() { testRing.Capacity = 10; }
);
}
/// <summary>Tests whether the Capacity property returns the current capacity</summary>
[Test]
public void TestCapacity() {
RingMemoryStream testRing = new RingMemoryStream(123);
Assert.AreEqual(123, testRing.Capacity);
}
/// <summary>Ensures that the CanRead property returns true</summary>
[Test]
public void TestCanRead() {
Assert.IsTrue(new RingMemoryStream(10).CanRead);
}
/// <summary>Ensures that the CanSeek property returns false</summary>
[Test]
public void TestCanSeek() {
Assert.IsFalse(new RingMemoryStream(10).CanSeek);
}
/// <summary>Ensures that the CanWrite property returns true</summary>
[Test]
public void TestCanWrite() {
Assert.IsTrue(new RingMemoryStream(10).CanWrite);
}
/// <summary>
/// Tests whether the auto reset feature works (resets the buffer pointer to the
/// left end of the buffer when it gets empty; mainly a performance feature).
/// </summary>
[Test]
public void TestAutoReset() {
byte[] tempBytes = new byte[10];
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(this.testBytes, 0, 8);
testRing.Read(tempBytes, 0, 2);
testRing.Read(tempBytes, 0, 2);
testRing.Read(tempBytes, 0, 1);
testRing.Read(tempBytes, 0, 1);
Assert.AreEqual(2, testRing.Length);
}
/// <summary>
/// Verifies that an exception is thrown when the Position property of the ring
/// memory stream is used to retrieve the current file pointer position
/// </summary>
[Test]
public void TestThrowOnRetrievePosition() {
Assert.Throws<NotSupportedException>(
delegate() { Console.WriteLine(new RingMemoryStream(10).Position); }
);
}
/// <summary>
/// Verifies that an exception is thrown when the Position property of the ring
/// memory stream is used to modify the current file pointer position
/// </summary>
[Test]
public void TestThrowOnAssignPosition() {
Assert.Throws<NotSupportedException>(
delegate() { new RingMemoryStream(10).Position = 0; }
);
}
/// <summary>
/// Verifies that an exception is thrown when the Seek() method of the ring memory
/// stream is attempted to be used
/// </summary>
[Test]
public void TestThrowOnSeek() {
Assert.Throws<NotSupportedException>(
delegate() { new RingMemoryStream(10).Seek(0, SeekOrigin.Begin); }
);
}
/// <summary>
/// Verifies that an exception is thrown when the SetLength() method of the ring
/// memory stream is attempted to be used
/// </summary>
[Test]
public void TestThrowOnSetLength() {
Assert.Throws<NotSupportedException>(
delegate() { new RingMemoryStream(10).SetLength(10); }
);
}
/// <summary>
/// Tests the Flush() method of the ring memory stream, which is either a dummy
/// implementation or has no side effects
/// </summary>
[Test]
public void TestFlush() {
new RingMemoryStream(10).Flush();
}
/// <summary>
/// Tests whether the length property is updated in accordance to the data written
/// into the ring memory stream
/// </summary>
[Test]
public void TestLengthOnLinearBlock() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(new byte[10], 0, 10);
Assert.AreEqual(10, testRing.Length);
}
/// <summary>
/// Tests whether the length property is updated in accordance to the data written
/// into the ring memory stream when the data is split within the stream
/// </summary>
[Test]
public void TestLengthOnSplitBlock() {
RingMemoryStream testRing = new RingMemoryStream(10);
testRing.Write(new byte[10], 0, 10);
testRing.Read(new byte[5], 0, 5);
testRing.Write(new byte[5], 0, 5);
Assert.AreEqual(10, testRing.Length);
}
/// <summary>Test data for the ring buffer unit tests</summary>
private byte[] testBytes;
}
} // namespace Nuclex.Support.IO
#endif // UNITTEST