Skip to content

Commit e593db5

Browse files
Improved coverage. Fixed issues with methods.
1 parent d208fda commit e593db5

4 files changed

Lines changed: 86 additions & 19 deletions

File tree

Source/Extensions._.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ public static void WriteLineNoTabs(this TextWriter writer, string? s = null)
333333
if (writer is null) throw new ArgumentNullException(nameof(writer));
334334
Contract.EndContractBlock();
335335

336-
if (s != null) writer.Write(s);
336+
if (s is not null) writer.Write(s);
337337
writer.Write(NEWLINE);
338338
}
339339

@@ -345,7 +345,7 @@ public static void WriteLineNoTabs(this TextWriter writer, string? s = null)
345345
/// <param name="values">The values to inject.</param>
346346
/// <param name="cultureInfo">The optional culture info. Default is invariant.</param>
347347
/// <returns>The resultant string.</returns>
348-
public static string Supplant<T>(this string format, T[] values, CultureInfo? cultureInfo = default)
348+
public static string Supplant<T>(this string format, T[]? values, CultureInfo? cultureInfo = default)
349349
=> values is null ? format : values.Length switch
350350
{
351351
0 => format,

Source/Open.Text.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<RepositoryUrl>https://github.com/Open-NET-Libraries/Open.Text</RepositoryUrl>
1818
<RepositoryType>git</RepositoryType>
1919
<PackageTags>dotnet, dotnetcore, string, span, readonlyspan, text, format, split, trim, equals, trimmed equals, first, last, preceding, following, stringbuilder, extensions</PackageTags>
20-
<Version>3.2.0</Version>
20+
<Version>3.2.1</Version>
2121
<PackageReleaseNotes></PackageReleaseNotes>
2222
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2323
<PublishRepositoryUrl>true</PublishRepositoryUrl>

Source/StringSegment.cs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,36 +61,38 @@ public override string ToString()
6161
/// <summary>
6262
/// Gets the string segment that precedes this one.
6363
/// </summary>
64-
public StringSegment Preceding()
65-
=> IsValid ? Create(Source, 0, Index) : default;
64+
/// <param name="includeSegment">When true, will include this segment.</param>
65+
public StringSegment Preceding(bool includeSegment = false)
66+
=> IsValid ? Create(Source, 0, includeSegment ? (Index + Length) : Index) : default;
6667

6768
/// <summary>
6869
/// Gets the string segment that follows this one.
6970
/// </summary>
70-
public StringSegment Following()
71-
=> IsValid ? Create(Source, Index + Length) : default;
71+
/// <param name="includeSegment">When true, will include this segment.</param>
72+
public StringSegment Following(bool includeSegment = false)
73+
=> IsValid ? Create(Source, includeSegment ? Index : (Index + Length)) : default;
7274

7375
/// <inheritdoc cref="Preceding"/>
7476
/// <param name="maxCharacters">The max number of characters to get.</param>
75-
public StringSegment Preceding(int maxCharacters)
77+
public StringSegment Preceding(int maxCharacters, bool includeSegment = false)
7678
{
7779
if (maxCharacters < 0) throw new ArgumentOutOfRangeException(nameof(maxCharacters), maxCharacters, "Must be at least zero.");
7880
if (!IsValid) return default;
79-
if (maxCharacters == 0) return new(Source, Index, 0);
81+
if (maxCharacters == 0) return includeSegment ? this : new(Source, Index, 0);
8082
var start = Math.Max(0, Index - maxCharacters);
81-
return new(Source, start, Index - start);
83+
return new(Source, start, includeSegment ? (Index - start + Length) : (Index - start));
8284
}
8385

8486
/// <inheritdoc cref="Following"/>
8587
/// <param name="maxCharacters">The max number of characters to get.</param>
86-
public StringSegment Following(int maxCharacters)
88+
public StringSegment Following(int maxCharacters, bool includeSegment = false)
8789
{
8890
if (maxCharacters < 0) throw new ArgumentOutOfRangeException(nameof(maxCharacters), maxCharacters, "Must be at least zero.");
8991
if (!IsValid) return default;
90-
var start = Index + Length;
91-
if (maxCharacters == 0) return new(Source, start, 0);
92-
var len = Source.Length;
93-
return new(Source, start, Math.Min(maxCharacters, len - start));
92+
var start = includeSegment ? Index : (Index + Length);
93+
if (maxCharacters == 0) return includeSegment ? this : new(Source, start, 0);
94+
var len = Math.Min(includeSegment ? (maxCharacters + Length) : maxCharacters, Source.Length - start);
95+
return new(Source, start, len);
9496
}
9597

9698
/// <summary>
@@ -130,7 +132,11 @@ public StringSegment OffsetLength(int offset)
130132
/// </param>
131133
public StringSegment Slice(int offset, int length, bool ignoreLengthBoundary = false)
132134
{
133-
if (!IsValid) return default;
135+
if (!IsValid)
136+
{
137+
if (offset == 0 && length == 0) return this;
138+
throw new InvalidOperationException("Cannot slice a null value.");
139+
}
134140
var newIndex = Index + offset;
135141
if (newIndex < 0) throw new ArgumentOutOfRangeException(nameof(offset), offset, "Cannot index less than the start of the string.");
136142
var newEnd = newIndex + length;
@@ -142,7 +148,7 @@ public StringSegment Slice(int offset, int length, bool ignoreLengthBoundary = f
142148
if (newIndex > end) throw new ArgumentOutOfRangeException(nameof(offset), offset, "Index is greater than the end of the source string.");
143149
throw new ArgumentOutOfRangeException(nameof(length), length, "Desired length will extend greater than the end of the source string.");
144150
}
145-
return new(Source, newIndex, end);
151+
return new(Source, newIndex, length);
146152
}
147153
else
148154
{
@@ -152,7 +158,7 @@ public StringSegment Slice(int offset, int length, bool ignoreLengthBoundary = f
152158
if (newIndex > end) throw new ArgumentOutOfRangeException(nameof(offset), offset, "Index is greater than the length of the segment.");
153159
throw new ArgumentOutOfRangeException(nameof(length), length, "Desired length will extend greater than the length of the segment.");
154160
}
155-
return new(Source, newIndex, end);
161+
return new(Source, newIndex, length);
156162
}
157163

158164
}
@@ -163,6 +169,21 @@ public StringSegment Slice(int offset, int length, bool ignoreLengthBoundary = f
163169
public bool Equals(StringSegment other)
164170
=> Index == other.Index & Length == other.Length && Source == other.Source;
165171

172+
173+
/// <inheritdoc cref="string.Equals(string, StringComparison)">
174+
public bool Equals(string? other, StringComparison stringComparison = StringComparison.Ordinal)
175+
{
176+
if (other is null) return !IsValid;
177+
if (other.Length != Length) return false;
178+
return AsSpan().Equals(other, stringComparison);
179+
}
180+
181+
public bool Equals(in ReadOnlySpan<char> other, StringComparison stringComparison = StringComparison.Ordinal)
182+
{
183+
if (other.Length != Length) return false;
184+
return AsSpan().Equals(other, stringComparison);
185+
}
186+
166187
/// <inheritdoc />
167188
public override bool Equals(object? obj)
168189
=> obj is StringSegment segment && Equals(segment);

Tests/BeforeAfterTests.cs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ namespace Open.Text.Tests
55
{
66
public static class BeforeAfterTests
77
{
8+
[Fact]
9+
public static void Validity()
10+
{
11+
var s = default(StringSegment);
12+
Assert.False(s.IsValid);
13+
Assert.Equal(s, s.SourceSegment);
14+
Assert.True(s.Slice(0, 0) == s);
15+
Assert.Throws<InvalidOperationException>(() => s.Slice(1, 1));
16+
Assert.True(s == s.SourceSegment);
17+
Assert.NotEqual(0, s.ToString().Length); // base string.
18+
Assert.Equal(0, ((ReadOnlySpan<char>)s).Length);
19+
Assert.Equal(0, ((ReadOnlyMemory<char>)s).Length);
20+
}
21+
822
[Theory]
923
[InlineData("Hello well how are you", "o", "Hell")]
1024
[InlineData("Hello well how are you", "ll", "He")]
@@ -15,7 +29,14 @@ public static void BeforeFirst(string source, string pattern, string? expected,
1529
{
1630
var first = source.First(pattern, comparisonType);
1731
if (expected is null) Assert.False(first.IsValid);
18-
else Assert.Equal(expected, first.Preceding().ToString());
32+
else
33+
{
34+
var p = first.Preceding();
35+
Assert.Equal(expected, p.ToString());
36+
Assert.True(p.ToString().Equals(expected, comparisonType));
37+
Assert.True(p.AsSpan().Equals(expected, comparisonType));
38+
Assert.True(p.AsMemory().Span.Equals(expected, comparisonType));
39+
}
1940
}
2041

2142
[Theory]
@@ -61,12 +82,37 @@ public static void AfterLast(string source, string pattern, string? expected, St
6182
public static void Offsets()
6283
{
6384
var segment = "Hello well how are you".First("well how");
85+
Assert.Equal("Hello ", segment.Preceding(100).ToString());
86+
Assert.Equal("o ", segment.Preceding(2).ToString());
87+
Assert.Equal(" are you", segment.Following(100).ToString());
88+
Assert.Equal(" a", segment.Following(2).ToString());
89+
Assert.Equal("Hello well how", segment.Preceding(100, true).ToString());
90+
Assert.Equal("o well how", segment.Preceding(2, true).ToString());
91+
Assert.Equal("well how are you", segment.Following(100, true).ToString());
92+
Assert.Equal("well how a", segment.Following(2, true).ToString());
93+
Assert.Equal("well how", segment.ToString());
6494
Assert.Equal("well", segment.OffsetLength(-4).ToString());
6595
Assert.Equal("how", segment.OffsetIndex(+5).ToString());
6696
Assert.Equal("well how are", segment.OffsetLength(+4).ToString());
6797
Assert.Equal("Hello well how", segment.OffsetIndex(-6).ToString());
6898
Assert.Throws<ArgumentOutOfRangeException>(() => segment.OffsetIndex(-7));
6999
Assert.Throws<ArgumentOutOfRangeException>(() => segment.OffsetLength(9));
70100
}
101+
102+
[Fact]
103+
public static void Slice()
104+
{
105+
var segment = "Hello well how are you".First("well how");
106+
Assert.Equal("well how", segment.ToString());
107+
var slice = segment.Slice(0, 4);
108+
Assert.Equal("well", slice.ToString());
109+
Assert.True(slice.Equals("well".AsSpan()));
110+
Assert.Throws<ArgumentOutOfRangeException>(() => slice.Slice(5, 5));
111+
Assert.Throws<ArgumentOutOfRangeException>(() => slice.Slice(0, 5));
112+
Assert.True(slice.Slice(1, 6, true).Equals("ell ho"));
113+
Assert.True(slice.Slice(1, 7, true).Equals("ell how"));
114+
Assert.True(slice.Slice(1, 15, true).Equals("ell how are you"));
115+
Assert.Throws<ArgumentOutOfRangeException>(() => slice.Slice(1, 16, true));
116+
}
71117
}
72118
}

0 commit comments

Comments
 (0)