From 195ba1df30e292d594195a33f85bf25350e02bcc Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Thu, 27 Nov 2008 19:04:09 +0000 Subject: [PATCH] Reformatted the comments in the RingMemoryStream class so my favorite IDE (Visual Studio) will not destroy indentation on auto-formatting anymore; achieved 100% test coverage for the RingMemoryStream and ReverseComparer classes git-svn-id: file:///srv/devel/repo-conversion/nusu@96 d2e56fa2-650e-0410-a79f-9358c0239efd --- Nuclex.Support.csproj | 3 + Source/Collections/ReverseComparer.Test.cs | 118 ++++++++++ Source/Collections/RingMemoryStream.Test.cs | 229 +++++++++++++++++--- Source/Collections/RingMemoryStream.cs | 27 +-- 4 files changed, 328 insertions(+), 49 deletions(-) create mode 100644 Source/Collections/ReverseComparer.Test.cs diff --git a/Nuclex.Support.csproj b/Nuclex.Support.csproj index 0df9c9a..3400830 100644 --- a/Nuclex.Support.csproj +++ b/Nuclex.Support.csproj @@ -82,6 +82,9 @@ + + ReverseComparer.cs + RingMemoryStream.cs diff --git a/Source/Collections/ReverseComparer.Test.cs b/Source/Collections/ReverseComparer.Test.cs new file mode 100644 index 0000000..932f0b2 --- /dev/null +++ b/Source/Collections/ReverseComparer.Test.cs @@ -0,0 +1,118 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; + +#if UNITTEST + +using NUnit.Framework; +using NMock2; + +namespace Nuclex.Support.Collections { + + /// Unit Test for the ReverseComparer helper class + [TestFixture] + public class ReverseComparerTest { + + #region class FortyTwoComparer + + /// Special comparer in which 42 is larger than everything + private class FortyTwoComparer : IComparer { + + /// Compares the left value to the right value + /// Value on the left side + /// Value on the right side + /// The relationship of the two values + public int Compare(int left, int right) { + + // Is there a 42 in the arguments? + if(left == 42) { + if(right == 42) { + return 0; // both are equal + } else { + return +1; // left is larger + } + } else if(right == 42) { + return -1; // right is larger + } + + // No 42 encountered, proceed as normal + return Math.Sign(left - right); + + } + + } + + #endregion // class FortyTwoComparer + + /// + /// Tests whether the default constructor of the reverse comparer works + /// + [Test] + public void TestDefaultConstructor() { + new ReverseComparer(); + } + + /// + /// Tests whether the full constructor of the reverse comparer works + /// + [Test] + public void TestFullConstructor() { + new ReverseComparer(new FortyTwoComparer()); + } + + /// + /// Tests whether the full constructor of the reverse comparer works + /// + [Test] + public void TestReversedDefaultComparer() { + Comparer comparer = Comparer.Default; + ReverseComparer reverseComparer = new ReverseComparer(comparer); + + Assert.Greater(0, comparer.Compare(10, 20)); + Assert.Less(0, comparer.Compare(20, 10)); + + Assert.Less(0, reverseComparer.Compare(10, 20)); + Assert.Greater(0, reverseComparer.Compare(20, 10)); + } + + /// + /// Tests whether the full constructor of the reverse comparer works + /// + [Test] + public void TestReversedCustomComparer() { + FortyTwoComparer fortyTwoComparer = new FortyTwoComparer(); + ReverseComparer reverseFortyTwoComparer = new ReverseComparer( + fortyTwoComparer + ); + + Assert.Less(0, fortyTwoComparer.Compare(42, 84)); + Assert.Greater(0, fortyTwoComparer.Compare(84, 42)); + + Assert.Greater(0, reverseFortyTwoComparer.Compare(42, 84)); + Assert.Less(0, reverseFortyTwoComparer.Compare(84, 42)); + } + + } + +} // namespace Nuclex.Support.Collections + +#endif // UNITTEST diff --git a/Source/Collections/RingMemoryStream.Test.cs b/Source/Collections/RingMemoryStream.Test.cs index 2668739..d71794d 100644 --- a/Source/Collections/RingMemoryStream.Test.cs +++ b/Source/Collections/RingMemoryStream.Test.cs @@ -19,6 +19,7 @@ License along with this library #endregion using System; +using System.IO; #if UNITTEST @@ -42,7 +43,7 @@ namespace Nuclex.Support.Collections { /// Ensures that the ring buffer blocks write attempts that would exceed its capacity /// [Test, ExpectedException(typeof(OverflowException))] - public void TestTooLargeChunk() { + public void TestWriteTooLargeChunk() { new RingMemoryStream(10).Write(this.testBytes, 0, 11); } @@ -51,41 +52,100 @@ namespace Nuclex.Support.Collections { /// entire buffer in one go. /// [Test] - public void TestBarelyFittingChunk() { + public void TestWriteBarelyFittingChunk() { new RingMemoryStream(10).Write(this.testBytes, 0, 10); } + /// + /// Ensures that the ring buffer correctly manages write attempts that have to + /// be split at the end of the ring buffer + /// + [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); + } + + /// + /// Ensures that the ring buffer correctly manages write attempts that write into + /// the gap after the ring buffer's data has become split + /// + [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); + } + + /// + /// 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 + /// + [Test, ExpectedException(typeof(OverflowException))] + 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); + testRing.Write(this.testBytes, 0, 3); + } + /// Tests whether the ring buffer correctly handles fragmentation [Test] - public void TestSplitBlockRead() { - RingMemoryStream rms = new RingMemoryStream(10); - rms.Write(this.testBytes, 0, 10); - rms.Read(this.testBytes, 0, 5); - rms.Write(this.testBytes, 0, 5); + 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]; - rms.Read(actual, 0, 10); + testRing.Read(actual, 0, 10); Assert.AreEqual(new byte[] { 5, 6, 7, 8, 9, 0, 1, 2, 3, 4 }, actual); } + /// Tests whether the ring buffer correctly handles fragmentation + [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); + } + /// /// Tests whether the ring buffer correctly returns partial data if more /// data is requested than is contained in it. /// [Test] public void TestEndOfStream() { - byte[] temp = new byte[10]; + byte[] tempBytes = new byte[10]; - RingMemoryStream rms = new RingMemoryStream(10); - Assert.AreEqual(0, rms.Read(temp, 0, 5)); + RingMemoryStream testRing = new RingMemoryStream(10); + Assert.AreEqual(0, testRing.Read(tempBytes, 0, 5)); - rms.Write(this.testBytes, 0, 5); - Assert.AreEqual(5, rms.Read(temp, 0, 10)); + testRing.Write(this.testBytes, 0, 5); + Assert.AreEqual(5, testRing.Read(tempBytes, 0, 10)); - rms.Write(this.testBytes, 0, 6); - rms.Read(temp, 0, 5); - rms.Write(this.testBytes, 0, 9); - Assert.AreEqual(10, rms.Read(temp, 0, 20)); + 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)); } /// @@ -93,12 +153,12 @@ namespace Nuclex.Support.Collections { /// [Test] public void TestCapacityIncrease() { - RingMemoryStream rms = new RingMemoryStream(10); - rms.Write(this.testBytes, 0, 10); + RingMemoryStream testRing = new RingMemoryStream(10); + testRing.Write(this.testBytes, 0, 10); - rms.Capacity = 20; + testRing.Capacity = 20; byte[] actual = new byte[10]; - rms.Read(actual, 0, 10); + testRing.Read(actual, 0, 10); Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, actual); } @@ -108,12 +168,12 @@ namespace Nuclex.Support.Collections { /// [Test] public void TestCapacityDecrease() { - RingMemoryStream rms = new RingMemoryStream(20); - rms.Write(this.testBytes, 0, 10); + RingMemoryStream testRing = new RingMemoryStream(20); + testRing.Write(this.testBytes, 0, 10); - rms.Capacity = 10; + testRing.Capacity = 10; byte[] actual = new byte[10]; - rms.Read(actual, 0, 10); + testRing.Read(actual, 0, 10); Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, actual); } @@ -124,10 +184,36 @@ namespace Nuclex.Support.Collections { /// [Test, ExpectedException(typeof(ArgumentOutOfRangeException))] public void TestCapacityDecreaseException() { - RingMemoryStream rms = new RingMemoryStream(20); - rms.Write(this.testBytes, 0, 20); + RingMemoryStream testRing = new RingMemoryStream(20); + testRing.Write(this.testBytes, 0, 20); - rms.Capacity = 10; + testRing.Capacity = 10; + } + + /// Tests whether the Capacity property returns the current capacity + [Test] + public void TestCapacity() { + RingMemoryStream testRing = new RingMemoryStream(123); + + Assert.AreEqual(123, testRing.Capacity); + } + + /// Ensures that the CanRead property returns true + [Test] + public void TestCanRead() { + Assert.IsTrue(new RingMemoryStream(10).CanRead); + } + + /// Ensures that the CanSeek property returns false + [Test] + public void TestCanSeek() { + Assert.IsFalse(new RingMemoryStream(10).CanSeek); + } + + /// Ensures that the CanWrite property returns true + [Test] + public void TestCanWrite() { + Assert.IsTrue(new RingMemoryStream(10).CanWrite); } /// @@ -136,17 +222,88 @@ namespace Nuclex.Support.Collections { /// [Test] public void TestAutoReset() { - RingMemoryStream rms = new RingMemoryStream(10); + byte[] tempBytes = new byte[10]; + RingMemoryStream testRing = new RingMemoryStream(10); - byte[] temp = new byte[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); - rms.Write(this.testBytes, 0, 8); - rms.Read(temp, 0, 2); - rms.Read(temp, 0, 2); - rms.Read(temp, 0, 1); - rms.Read(temp, 0, 1); + Assert.AreEqual(2, testRing.Length); + } - Assert.AreEqual(2, rms.Length); + /// + /// Verifies that an exception is thrown when the Position property of the ring + /// memory stream is used to retrieve the current file pointer position + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRetrievePosition() { + long position = new RingMemoryStream(10).Position; + } + + /// + /// Verifies that an exception is thrown when the Position property of the ring + /// memory stream is used to modify the current file pointer position + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnAssignPosition() { + new RingMemoryStream(10).Position = 0; + } + + /// + /// Verifies that an exception is thrown when the Seek() method of the ring memory + /// stream is attempted to be used + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnSeek() { + new RingMemoryStream(10).Seek(0, SeekOrigin.Begin); + } + + /// + /// Verifies that an exception is thrown when the SetLength() method of the ring + /// memory stream is attempted to be used + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnSetLength() { + new RingMemoryStream(10).SetLength(10); + } + + /// + /// Tests the Flush() method of the ring memory stream, which is either a dummy + /// implementation or has no side effects + /// + [Test] + public void TestFlush() { + new RingMemoryStream(10).Flush(); + } + + /// + /// Tests whether the length property is updated in accordance to the data written + /// into the ring memory stream + /// + [Test] + public void TestLengthOnLinearBlock() { + RingMemoryStream testRing = new RingMemoryStream(10); + testRing.Write(new byte[10], 0, 10); + + Assert.AreEqual(10, testRing.Length); + } + + /// + /// 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 + /// + [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); } /// Test data for the ring buffer unit tests diff --git a/Source/Collections/RingMemoryStream.cs b/Source/Collections/RingMemoryStream.cs index aff97ed..9b005fa 100644 --- a/Source/Collections/RingMemoryStream.cs +++ b/Source/Collections/RingMemoryStream.cs @@ -126,9 +126,10 @@ namespace Nuclex.Support.Collections { } } - // The end index lies before the start index, so the data in the - // ring memory stream is fragmented. Example: |#####>-------<#####| - } else { + } else { // The end index lies in front of the start index + + // With the end before the start index, the data in the ring memory + // stream is fragmented. Example: |#####>-------<#####| int linearAvailable = (int)this.ringBuffer.Length - this.startIndex; // Will this read process cross the end of the ring buffer, requiring us to @@ -145,18 +146,19 @@ namespace Nuclex.Support.Collections { this.startIndex = count - linearAvailable; this.ringBuffer.Read(buffer, offset + linearAvailable, this.startIndex); - // Nope, the amount of requested data can be read in one piece without - // crossing the end of the ring buffer - } else { + } else { // Nope, the amount of requested data can be read in one piece this.ringBuffer.Position = this.startIndex; this.ringBuffer.Read(buffer, offset, count); this.startIndex += count; } + // If we consumed the entire ring buffer, set the empty flag and move + // the indexes back to zero for better performance if(this.startIndex == this.endIndex) { setEmpty(); } + } return count; @@ -187,9 +189,7 @@ namespace Nuclex.Support.Collections { this.endIndex = count - linearAvailable; this.ringBuffer.Write(buffer, offset + linearAvailable, this.endIndex); - // All data can be appended at the current stream position without - // crossing the ring memory stream's end - } else { + } else { // All data can be appended at the current stream position this.ringBuffer.Position = this.endIndex; this.ringBuffer.Write(buffer, offset, count); this.endIndex += count; @@ -197,10 +197,10 @@ namespace Nuclex.Support.Collections { this.empty = false; - // The end index lies before the start index, so the data in the ring memory - // stream has been fragmented. This means the gap into which we are about - // to write is not fragmented. Example: |#####>-------<#####| - } else { + } else { // The end index lies before the start index + + // The ring memory stream has been fragmented. This means the gap into which + // we are about to write is not fragmented. Example: |#####>-------<#####| if(count > (this.startIndex - this.endIndex)) throw new OverflowException("Data does not fit in buffer"); @@ -209,6 +209,7 @@ namespace Nuclex.Support.Collections { this.ringBuffer.Position = this.endIndex; this.ringBuffer.Write(buffer, offset, count); this.endIndex += count; + } }