From c7dd57f59f60e089e6cee875b01bab2486c59ad6 Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Wed, 2 Nov 2022 18:05:04 +0000 Subject: [PATCH] Added ListSegment class which is analogous to StringSegment and ArraySegment, but for IList git-svn-id: file:///srv/devel/repo-conversion/nusu@336 d2e56fa2-650e-0410-a79f-9358c0239efd --- Nuclex.Support (net-4.0).csproj | 680 +++++++++++++------------ Source/Collections/ListSegment.Test.cs | 257 ++++++++++ Source/Collections/ListSegment.cs | 281 ++++++++++ Source/StringSegment.Test.cs | 66 +-- Source/StringSegment.cs | 20 +- 5 files changed, 907 insertions(+), 397 deletions(-) create mode 100644 Source/Collections/ListSegment.Test.cs create mode 100644 Source/Collections/ListSegment.cs diff --git a/Nuclex.Support (net-4.0).csproj b/Nuclex.Support (net-4.0).csproj index 2231bc5..1b25d10 100644 --- a/Nuclex.Support (net-4.0).csproj +++ b/Nuclex.Support (net-4.0).csproj @@ -1,346 +1,348 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {00567408-4F44-4C00-866E-B04A99E482F2} - Library - Properties - Nuclex.Support - Nuclex.Support - v4.0 - 512 - Client - - - true - full - false - bin\net-4.0\Debug\ - TRACE;DEBUG;UNITTEST;WINDOWS - prompt - 4 - bin\net-4.0\Debug\Nuclex.Support.xml - - - pdbonly - true - bin\net-4.0\Release\ - TRACE;UNITTEST;WINDOWS - prompt - 4 - bin\net-4.0\Release\Nuclex.Support.xml - - - true - - - ..\Foundation.snk - - - - ..\References\nmock\net-4.0\NMock.StrongNamed.dll - - - False - ..\References\nunit\net-4.0\framework\nunit.framework.dll - - - - - - - - - - - - - - - - - - - - - - ExpressionTreeCloner.cs - - - ExpressionTreeCloner.cs - - - ExpressionTreeCloner.cs - - - - - ReflectionCloner.cs - - - - - SerializationCloner.cs - - - - Constants.cs - - - - Deque.cs - - - Deque.cs - - - Deque.cs - - - Deque.cs - - - Deque.cs - - - - - - - ItemEventArgs.cs - - - - ItemReplaceEventArgs.cs - - - - MultiDictionary.cs - - - MultiDictionary.cs - - - MultiDictionary.cs - - - - ObservableCollection.cs - - - - ObservableDictionary.cs - - - - ObservableList.cs - - - - ObservableSet.cs - - - - PairPriorityQueue.cs - - - - Parentable.cs - - - - ParentingCollection.cs - - - - Pool.cs - - - - PriorityItemPair.cs - - - - PriorityQueue.cs - - - - ReadOnlyCollection.cs - - - - ReadOnlyDictionary.cs - - - - ReadOnlyList.cs - - - - ReadOnlySet.cs - - - - ReverseComparer.cs - - - - TransformingReadOnlyCollection.cs - - - TransformingReadOnlyCollection.cs - - - - Variegator.cs - - - - WeakCollection.cs - - - WeakCollection.cs - - - - ConfigurationFileStore.cs - - - ConfigurationFileStore.cs - - - - - MemoryStore.cs - - - - - WindowsRegistryStore.cs - - - - - PartialStream.cs - - - - RingMemoryStream.cs - - - - ChainStream.cs - - - - LicenseKey.cs - - - - CommandLine.cs - - - CommandLine.cs - - - CommandLine.cs - - - CommandLine.cs - - - - ParserHelper.cs - - - - PropertyChangedEventArgsHelper.cs - - - - EnumHelper.cs - - - - Observable.cs - - - - ObservableHelper.cs - - - - AffineThreadPool.cs - - - - - ParallelBackgroundWorker.cs - - - - ThreadRunner.cs - - - - TypeHelper.cs - - - - FloatHelper.cs - - - - IntegerHelper.cs - - - - PathHelper.cs - - - - Shared.cs - - - - StringBuilderHelper.cs - - - - StringHelper.cs - - - - StringSegment.cs - - - - WeakReference.cs - - - - XmlHelper.cs - - - - - Foundation.snk - - - - - - - - + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {00567408-4F44-4C00-866E-B04A99E482F2} + Library + Properties + Nuclex.Support + Nuclex.Support + v4.0 + 512 + Client + + + true + full + false + bin\net-4.0\Debug\ + TRACE;DEBUG;UNITTEST;WINDOWS + prompt + 4 + bin\net-4.0\Debug\Nuclex.Support.xml + + + pdbonly + true + bin\net-4.0\Release\ + TRACE;UNITTEST;WINDOWS + prompt + 4 + bin\net-4.0\Release\Nuclex.Support.xml + + + true + + + ..\Foundation.snk + + + + ..\References\nmock\net-4.0\NMock.StrongNamed.dll + + + False + ..\References\nunit\net-4.0\framework\nunit.framework.dll + + + + + + + + + + + + + + + + + + + + + + ExpressionTreeCloner.cs + + + ExpressionTreeCloner.cs + + + ExpressionTreeCloner.cs + + + + + ReflectionCloner.cs + + + + + SerializationCloner.cs + + + + Constants.cs + + + + Deque.cs + + + Deque.cs + + + Deque.cs + + + Deque.cs + + + Deque.cs + + + + + + + ItemEventArgs.cs + + + + ItemReplaceEventArgs.cs + + + + + + MultiDictionary.cs + + + MultiDictionary.cs + + + MultiDictionary.cs + + + + ObservableCollection.cs + + + + ObservableDictionary.cs + + + + ObservableList.cs + + + + ObservableSet.cs + + + + PairPriorityQueue.cs + + + + Parentable.cs + + + + ParentingCollection.cs + + + + Pool.cs + + + + PriorityItemPair.cs + + + + PriorityQueue.cs + + + + ReadOnlyCollection.cs + + + + ReadOnlyDictionary.cs + + + + ReadOnlyList.cs + + + + ReadOnlySet.cs + + + + ReverseComparer.cs + + + + TransformingReadOnlyCollection.cs + + + TransformingReadOnlyCollection.cs + + + + Variegator.cs + + + + WeakCollection.cs + + + WeakCollection.cs + + + + ConfigurationFileStore.cs + + + ConfigurationFileStore.cs + + + + + MemoryStore.cs + + + + + WindowsRegistryStore.cs + + + + + PartialStream.cs + + + + RingMemoryStream.cs + + + + ChainStream.cs + + + + LicenseKey.cs + + + + CommandLine.cs + + + CommandLine.cs + + + CommandLine.cs + + + CommandLine.cs + + + + ParserHelper.cs + + + + PropertyChangedEventArgsHelper.cs + + + + EnumHelper.cs + + + + Observable.cs + + + + ObservableHelper.cs + + + + AffineThreadPool.cs + + + + + ParallelBackgroundWorker.cs + + + + ThreadRunner.cs + + + + TypeHelper.cs + + + + FloatHelper.cs + + + + IntegerHelper.cs + + + + PathHelper.cs + + + + Shared.cs + + + + StringBuilderHelper.cs + + + + StringHelper.cs + + + + StringSegment.cs + + + + WeakReference.cs + + + + XmlHelper.cs + + + + + Foundation.snk + + + + + + + + + --> \ No newline at end of file diff --git a/Source/Collections/ListSegment.Test.cs b/Source/Collections/ListSegment.Test.cs new file mode 100644 index 0000000..d7da67b --- /dev/null +++ b/Source/Collections/ListSegment.Test.cs @@ -0,0 +1,257 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2017 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; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; + +namespace Nuclex.Support.Collections { + + /// Unit Test for the list segment class + [TestFixture] + internal class ListSegmentTest { + + /// + /// Tests whether the default constructor of the ListSegment class throws the + /// right exception when being passed 'null' instead of a list + /// + [Test] + public void SimpleConstructorThrowsWhenListIsNull() { + Assert.Throws( + delegate() { new ListSegment(null); } + ); + } + + /// + /// Tests whether the simple constructor of the ListSegment class accepts + /// an empty list + /// + [Test] + public void SimpleConstructorAcceptsEmptyList() { + new ListSegment(new List()); + } + + /// + /// Tests whether the full constructor of the ListSegment class throws the + /// right exception when being passed 'null' instead of a string + /// + [Test] + public void ConstructorThrowsWhenListIsNull() { + Assert.Throws( + delegate() { new ListSegment(null, 0, 0); } + ); + } + + /// + /// Tests whether the full constructor of the ListSegment class accepts + /// an empty string + /// + [Test] + public void ConstructorAcceptsEmptyList() { + new ListSegment(new List(), 0, 0); + } + + /// + /// Tests whether the full constructor of the ListSegment class throws the + /// right exception when being passed an invalid start offset + /// + [Test] + public void ConstructorThrowsOnInvalidOffset() { + Assert.Throws( + delegate() { new ListSegment(new List(), -1, 0); } + ); + } + + /// + /// Tests whether the full constructor of the ListSegment class throws the + /// right exception when being passed an invalid element count + /// + [Test] + public void ConstructorThrowsOnInvalidCount() { + Assert.Throws( + delegate() { new ListSegment(new List(), 0, -1); } + ); + } + + /// + /// Tests whether the full constructor of the ListSegment class throws the + /// right exception when being passed a string length that's too large + /// + [Test] + public void ConstructorThrowsOnListOverrun() { + var testList = new List(capacity: 5) { 1, 2, 3, 4, 5 }; + Assert.Throws( + delegate() { new ListSegment(testList, 3, 3); } + ); + } + + /// Tests whether the 'Text' property works as expected + [Test] + public void ListPropertyStoresOriginalList() { + var testList = new List(capacity: 5) { 1, 2, 3, 4, 5 }; + ListSegment testSegment = new ListSegment(testList, 1, 3); + Assert.AreSame(testList, testSegment.List); + } + + /// Tests whether the 'Offset' property works as expected + [Test] + public void OffsetPropertyIsStored() { + var testList = new List(capacity: 5) { 1, 2, 3, 4, 5 }; + ListSegment testSegment = new ListSegment(testList, 1, 3); + Assert.AreEqual(1, testSegment.Offset); + } + + /// Tests whether the 'Count' property works as expected + [Test] + public void CountPropertyIsStored() { + var testList = new List(capacity: 5) { 1, 2, 3, 4, 5 }; + ListSegment testSegment = new ListSegment(testList, 1, 3); + Assert.AreEqual(3, testSegment.Count); + } + + /// + /// Tests whether two differing instances produce different hash codes + /// + [Test] + public void DifferentInstancesHaveDifferentHashCodes_Usually() { + var forwardCountSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + var reverseCountSegment = new ListSegment( + new List(capacity: 9) { 9, 8, 7, 6, 5, 4, 3, 2, 1 }, 1, 8 + ); + + Assert.AreNotEqual( + forwardCountSegment.GetHashCode(), reverseCountSegment.GetHashCode() + ); + } + + /// + /// Tests whether two equivalent instances produce an identical hash code + /// + [Test] + public void EquivalentInstancesHaveSameHashcode() { + var testSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + var identicalSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + + Assert.AreEqual( + testSegment.GetHashCode(), identicalSegment.GetHashCode() + ); + } + + /// Tests the equals method performing a comparison against null + [Test] + public void EqualsAgainstNullIsAlwaysFalse() { + var testList = new List(capacity: 5) { 1, 2, 3, 4, 5 }; + ListSegment testSegment = new ListSegment(testList, 1, 3); + + Assert.IsFalse( + testSegment.Equals(null) + ); + } + + /// Tests the equality operator with differing instances + [Test] + public void DifferingInstancesAreNotEqual() { + var forwardCountSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + var reverseCountSegment = new ListSegment( + new List(capacity: 9) { 9, 8, 7, 6, 5, 4, 3, 2, 1 }, 1, 8 + ); + + Assert.IsFalse(forwardCountSegment == reverseCountSegment); + } + + /// Tests the equality operator with equivalent instances + [Test] + public void EquivalentInstancesAreEqual() { + var testSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + var identicalSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + + Assert.IsTrue(testSegment == identicalSegment); + } + + /// Tests the inequality operator with differing instances + [Test] + public void DifferingInstancesAreUnequal() { + var forwardCountSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + var reverseCountSegment = new ListSegment( + new List(capacity: 9) { 9, 8, 7, 6, 5, 4, 3, 2, 1 }, 1, 8 + ); + + Assert.IsTrue(forwardCountSegment != reverseCountSegment); + } + + /// Tests the inequality operator with equivalent instances + [Test] + public void EquivalentInstancesAreNotUnequal() { + var testSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + var identicalSegment = new ListSegment( + new List(capacity: 9) { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2, 7 + ); + + Assert.IsFalse(testSegment != identicalSegment); + } + + /// Tests the ToString() method of the string segment + [Test] + public void TestToString() { + var testList = new List(capacity: 6) { 1, 2, 3, 4, 5, 6 }; + ListSegment testSegment = new ListSegment(testList, 2, 2); + + string stringRepresentation = testSegment.ToString(); + StringAssert.Contains("3, 4", stringRepresentation); + StringAssert.DoesNotContain("2", stringRepresentation); + StringAssert.DoesNotContain("5", stringRepresentation); + } + + /// Tests whether the 'Text' property works as expected + [Test] + public void ToListReturnsSubset() { + var testList = new List(capacity: 5) { 1, 2, 3, 4, 5 }; + ListSegment testSegment = new ListSegment(testList, 1, 3); + CollectionAssert.AreEqual( + new List(capacity: 3) { 2, 3, 4 }, + testSegment.ToList() + ); + } + + } + +} // namespace Nuclex.Support.Collections + +#endif // UNITTEST diff --git a/Source/Collections/ListSegment.cs b/Source/Collections/ListSegment.cs new file mode 100644 index 0000000..ca47b4b --- /dev/null +++ b/Source/Collections/ListSegment.cs @@ -0,0 +1,281 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2017 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; +using System.Runtime.InteropServices; + +namespace Nuclex.Support.Collections { + + /// View into a section of an IList<T> without copying said string + /// + /// Type of elements that are stored in the list the segment references + /// + /// + /// + /// The design of this class pretty much mirrors that of the + /// class found in the .NET framework, but is + /// specialized to be used for IList<T>, which can not be cast to arrays + /// directly (and loses type safety). + /// + /// + /// In certain situations, passing a ListSegment instead of storing the selected + /// elements in a new list is useful. For example, the caller might want to know + /// from which index of the original list the section was taken. When the original + /// list needs to be modified, for example in a sorting algorithm, the list segment + /// can be used to specify a region for the algorithm to work on while still accessing + /// the original list. + /// + /// +#if !NO_SERIALIZATION + [Serializable, StructLayout(LayoutKind.Sequential)] +#endif + public struct ListSegment { + + /// + /// Initializes a new instance of the class + /// that delimits all the elements in the specified string + /// + /// List that will be wrapped + /// String is null + public ListSegment(IList list) { + if(list == null) { // questionable, but matches behavior of ArraySegment class + throw new ArgumentNullException("text", "Text must not be null"); + } + + this.list = list; + this.offset = 0; + this.count = list.Count; + } + + /// + /// Initializes a new instance of the class + /// that delimits the specified range of the elements in the specified string + /// + /// The list containing the range of elements to delimit + /// The zero-based index of the first element in the range + /// The number of elements in the range + /// + /// Offset or count is less than 0 + /// + /// + /// Offset and count do not specify a valid range in array + /// + /// String is null + public ListSegment(IList list, int offset, int count) { + if(list == null) { // questionable, but matches behavior of ArraySegment class + throw new ArgumentNullException("list"); + } + if(offset < 0) { + throw new ArgumentOutOfRangeException( + "offset", "Argument out of range, non-negative number required" + ); + } + if(count < 0) { + throw new ArgumentOutOfRangeException( + "count", "Argument out of range, non-negative number required" + ); + } + if(count > (list.Count - offset)) { + throw new ArgumentException( + "Invalid argument, specified offset and count exceed list size" + ); + } + + this.list = list; + this.offset = offset; + this.count = count; + } + + /// + /// Gets the original list containing the range of elements that the list + /// segment delimits + /// + /// + /// The original list that was passed to the constructor, and that contains the range + /// delimited by the + /// + public IList List { + get { return this.list; } + } + + /// + /// Gets the position of the first element in the range delimited by the list segment, + /// relative to the start of the original list + /// + /// + /// The position of the first element in the range delimited by the + /// , relative to the start of the original list + /// + public int Offset { + get { return this.offset; } + } + + /// + /// Gets the number of elements in the range delimited by the list segment + /// + /// + /// The number of elements in the range delimited by + /// the + /// + public int Count { + get { return this.count; } + } + + /// Returns the hash code for the current instance + /// A 32-bit signed integer hash code + public override int GetHashCode() { + int hashCode = this.offset ^ this.count; + for(int index = 0; index < this.count; ++index) { + hashCode ^= this.list[index + this.offset].GetHashCode(); + } + return hashCode; + } + + /// + /// Determines whether the specified object is equal to the current instance + /// + /// + /// True if the specified object is a structure + /// and is equal to the current instance; otherwise, false + /// + /// The object to be compared with the current instance + public override bool Equals(object other) { + return + (other is ListSegment) && + this.Equals((ListSegment)other); + } + + /// + /// Determines whether the specified + /// structure is equal to the current instance + /// + /// + /// True if the specified structure is equal + /// to the current instance; otherwise, false + /// + /// + /// The structure to be compared with + /// the current instance + /// + public bool Equals(ListSegment other) { + if(other.count != this.count) { + return false; + } + + if(ReferenceEquals(other.list, this.list)) { + return (other.offset == this.offset); + } else { + var comparer = Comparer.Default; + for(int index = 0; index < this.count; ++index) { + int difference = comparer.Compare( + other.list[index + other.offset], this.list[index + this.offset] + ); + if(difference != 0) { + return false; + } + } + } + return true; + } + + /// + /// Indicates whether two structures are equal + /// + /// True if a is equal to b; otherwise, false + /// + /// The structure on the left side of + /// the equality operator + /// + /// + /// The structure on the right side of + /// the equality operator + /// + public static bool operator ==(ListSegment left, ListSegment right) { + return left.Equals(right); + } + + /// + /// Indicates whether two structures are unequal + /// + /// True if a is not equal to b; otherwise, false + /// + /// The structure on the left side of + /// the inequality operator + /// + /// + /// The structure on the right side of + /// the inequality operator + /// + public static bool operator !=(ListSegment left, ListSegment right) { + return !(left == right); + } + + /// Returns a string representation of the list segment + /// The string representation of the list segment + public override string ToString() { + var builder = new System.Text.StringBuilder(); + builder.Append("ListSegment {"); + for(int index = 0; index < Math.Min(this.count, 10); ++index) { + if(index == 0) { + builder.Append(" "); + } else { + builder.Append(", "); + } + builder.Append(this.list[index + this.offset].ToString()); + } + + if(this.count >= 11) { + builder.Append(", ... }"); + } else { + builder.Append(" }"); + } + + return builder.ToString(); + } + + /// Returns a new list containing only the elements in the list segment + /// A new list containing only the elements in the list segment + public List ToList() { + if(this.count == 0) { + return new List(capacity: 0); + } else { + var newList = new List(capacity: this.count); + { + int endIndex = this.offset + this.count; + for(int index = this.offset; index < endIndex; ++index) { + newList.Add(this.list[index]); + } + } + + return newList; + } + } + + /// List wrapped by the list segment + private IList list; + /// Offset in the original list the segment begins at + private int offset; + /// Number of elements in the segment + private int count; + + } + +} // namespace Nuclex.Support.Collections diff --git a/Source/StringSegment.Test.cs b/Source/StringSegment.Test.cs index 98b89f5..52f8b04 100644 --- a/Source/StringSegment.Test.cs +++ b/Source/StringSegment.Test.cs @@ -27,7 +27,7 @@ using NUnit.Framework; namespace Nuclex.Support { - /// Unit Test for the strign segment class + /// Unit Test for the string segment class [TestFixture] internal class StringSegmentTest { @@ -36,7 +36,7 @@ namespace Nuclex.Support { /// right exception when being passed 'null' instead of a string /// [Test] - public void TestNullStringInSimpleConstructor() { + public void SimpleConstructorThrowsWhenStringIsNull() { Assert.Throws( delegate() { new StringSegment(null); } ); @@ -47,7 +47,7 @@ namespace Nuclex.Support { /// an empty string /// [Test] - public void TestEmptyStringInSimpleConstructor() { + public void SimpleConstructorAcceptsEmptyString() { new StringSegment(string.Empty); } @@ -56,7 +56,7 @@ namespace Nuclex.Support { /// right exception when being passed 'null' instead of a string /// [Test] - public void TestNullStringInFullConstructor() { + public void ConstructorThrowsWhenStringIsNull() { Assert.Throws( delegate() { new StringSegment(null, 0, 0); } ); @@ -67,7 +67,7 @@ namespace Nuclex.Support { /// an empty string /// [Test] - public void TestEmptyStringInFullConstructor() { + public void ConstructorAcceptsEmptyString() { new StringSegment(string.Empty, 0, 0); } @@ -76,7 +76,7 @@ namespace Nuclex.Support { /// right exception when being passed an invalid start offset /// [Test] - public void TestInvalidOffsetInConstructor() { + public void ConstructorThrowsOnInvalidOffset() { Assert.Throws( delegate() { new StringSegment(string.Empty, -1, 0); } ); @@ -87,7 +87,7 @@ namespace Nuclex.Support { /// right exception when being passed an invalid string length /// [Test] - public void TestInvalidLengthInConstructor() { + public void ConstructorThrowsOnInvalidLength() { Assert.Throws( delegate() { new StringSegment(string.Empty, 0, -1); } ); @@ -98,7 +98,7 @@ namespace Nuclex.Support { /// right exception when being passed a string length that's too large /// [Test] - public void TestExcessiveLengthInConstructor() { + public void ConstructorThrowsOnLengthOverrun() { Assert.Throws( delegate() { new StringSegment("hello", 3, 3); } ); @@ -106,21 +106,21 @@ namespace Nuclex.Support { /// Tests whether the 'Text' property works as expected [Test] - public void TestTextProperty() { + public void TextPropertyStoresOriginalString() { StringSegment testSegment = new StringSegment("hello", 1, 3); Assert.AreEqual("hello", testSegment.Text); } /// Tests whether the 'Offset' property works as expected [Test] - public void TestOffsetProperty() { + public void OffsetPropertyIsStored() { StringSegment testSegment = new StringSegment("hello", 1, 3); Assert.AreEqual(1, testSegment.Offset); } /// Tests whether the 'Count' property works as expected [Test] - public void TestCountProperty() { + public void CountPropertyIsStored() { StringSegment testSegment = new StringSegment("hello", 1, 3); Assert.AreEqual(3, testSegment.Count); } @@ -129,7 +129,7 @@ namespace Nuclex.Support { /// Tests whether two differing instances produce different hash codes /// [Test] - public void TestHashCodeOnDifferingInstances() { + public void DifferentInstancesHaveDifferentHashCodes_Usually() { StringSegment helloWorldSegment = new StringSegment("hello world", 2, 7); StringSegment howAreYouSegment = new StringSegment("how are you", 1, 9); @@ -142,7 +142,7 @@ namespace Nuclex.Support { /// Tests whether two equivalent instances produce an identical hash code /// [Test] - public void TestHashCodeOnEquivalentInstances() { + public void EquivalentInstancesHaveSameHashcode() { StringSegment helloWorld1Segment = new StringSegment("hello world", 2, 7); StringSegment helloWorld2Segment = new StringSegment("hello world", 2, 7); @@ -153,7 +153,7 @@ namespace Nuclex.Support { /// Tests the equals method performing a comparison against null [Test] - public void TestEqualsOnNull() { + public void EqualsAgainstNullIsAlwaysFalse() { StringSegment helloWorldSegment = new StringSegment("hello world", 2, 7); Assert.IsFalse( @@ -163,7 +163,7 @@ namespace Nuclex.Support { /// Tests the equality operator with differing instances [Test] - public void TestEqualityOnDifferingInstances() { + public void DifferingInstancesAreNotEqual() { StringSegment helloWorldSegment = new StringSegment("hello world", 2, 7); StringSegment howAreYouSegment = new StringSegment("how are you", 1, 9); @@ -172,7 +172,7 @@ namespace Nuclex.Support { /// Tests the equality operator with equivalent instances [Test] - public void TestEqualityOnEquivalentInstances() { + public void EquivalentInstancesAreEqual() { StringSegment helloWorld1Segment = new StringSegment("hello world", 2, 7); StringSegment helloWorld2Segment = new StringSegment("hello world", 2, 7); @@ -181,7 +181,7 @@ namespace Nuclex.Support { /// Tests the inequality operator with differing instances [Test] - public void TestInequalityOnDifferingInstances() { + public void DifferingInstancesAreUnequal() { StringSegment helloWorldSegment = new StringSegment("hello world", 2, 7); StringSegment howAreYouSegment = new StringSegment("how are you", 1, 9); @@ -190,7 +190,7 @@ namespace Nuclex.Support { /// Tests the inequality operator with equivalent instances [Test] - public void TestInequalityOnEquivalentInstances() { + public void EquivalentInstancesAreNotUnequal() { StringSegment helloWorld1Segment = new StringSegment("hello world", 2, 7); StringSegment helloWorld2Segment = new StringSegment("hello world", 2, 7); @@ -205,36 +205,6 @@ namespace Nuclex.Support { Assert.AreEqual("o w", helloWorldSegment.ToString()); } - /// - /// Tests the ToString() method of the string segment with an invalid string - /// - [Test] - public void TestToStringWithInvalidString() { - Assert.Throws( - delegate() { new StringSegment(null, 4, 3); } - ); - } - - /// - /// Tests the ToString() method of the string segment with an invalid offset - /// - [Test] - public void TestToStringWithInvalidOffset() { - Assert.Throws( - delegate() { new StringSegment("hello world", -4, 3); } - ); - } - - /// - /// Tests the ToString() method of the string segment with an invalid count - /// - [Test] - public void TestToStringWithInvalidCount() { - Assert.Throws( - delegate() { new StringSegment("hello world", 4, -3); } - ); - } - } } // namespace Nuclex.Support diff --git a/Source/StringSegment.cs b/Source/StringSegment.cs index 90fc9fa..8a847f5 100644 --- a/Source/StringSegment.cs +++ b/Source/StringSegment.cs @@ -23,7 +23,7 @@ using System.Runtime.InteropServices; namespace Nuclex.Support { - /// Delimits a section of a string + /// View into a section of a string without copying said string /// /// /// The design of this class pretty much mirrors that of the @@ -32,10 +32,10 @@ namespace Nuclex.Support { /// share a lot of the characteristics of an array. /// /// - /// In certain situations, passing a StringSegment instead of the the actual - /// section from a string is useful. For example, the caller might want to know - /// from which index of the original string the substring was taken. Used internally - /// in parsers, it can also prevent needless string copying and garbage generation. + /// In certain situations, passing a StringSegment instead of the actual copied + /// substring is useful. For example, the caller might want to know from which + /// index of the original string the substring was taken. Used internally in parsers, + /// it can also prevent needless string copying and garbage generation. /// /// #if !NO_SERIALIZATION @@ -103,7 +103,7 @@ namespace Nuclex.Support { /// segment delimits /// /// - /// The original array that was passed to the constructor, and that contains the range + /// The original string that was passed to the constructor, and that contains the range /// delimited by the /// public string Text { @@ -111,19 +111,19 @@ namespace Nuclex.Support { } /// - /// Gets the position of the first element in the range delimited by the array segment, - /// relative to the start of the original array + /// Gets the position of the first element in the range delimited by the string segment, + /// relative to the start of the original string /// /// /// The position of the first element in the range delimited by the - /// , relative to the start of the original array + /// , relative to the start of the original string /// public int Offset { get { return this.offset; } } /// - /// Gets the number of elements in the range delimited by the array segment + /// Gets the number of elements in the range delimited by the string segment /// /// /// The number of elements in the range delimited by the