|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#if NET35_UNITTEST
extern alias StringToolsNet35;
#endif
using System.Collections.Generic;
using Shouldly;
using Xunit;
#if NET35_UNITTEST
using StringToolsNet35::Microsoft.NET.StringTools;
#endif
#nullable disable
namespace Microsoft.NET.StringTools.Tests
{
public class SpanBasedStringBuilder_Tests
{
private SpanBasedStringBuilder MakeSpanBasedStringBuilder(InterningTestData.TestDatum datum, bool appendSubStrings = false)
{
bool wrapFirstFragment = datum.Fragments.Length > 0 && datum.Fragments[0] != null;
SpanBasedStringBuilder stringBuilder = wrapFirstFragment
? new SpanBasedStringBuilder(datum.Fragments[0])
: new SpanBasedStringBuilder();
for (int i = 1; i < datum.Fragments.Length; i++)
{
if (appendSubStrings)
{
int index = datum.Fragments[i].Length / 2;
stringBuilder.Append(datum.Fragments[i], 0, index);
stringBuilder.Append(datum.Fragments[i], index, datum.Fragments[i].Length - index);
}
else
{
stringBuilder.Append(datum.Fragments[i]);
}
}
return stringBuilder;
}
public static IEnumerable<object[]> TestData => InterningTestData.TestData;
public static IEnumerable<object[]> TestDataForTrim => InterningTestData.TestDataForTrim;
[Theory]
[MemberData(nameof(TestData))]
public void LengthReturnsLength(InterningTestData.TestDatum datum)
{
using var stringBuilder = MakeSpanBasedStringBuilder(datum);
stringBuilder.Length.ShouldBe(datum.Length);
}
[Theory]
[MemberData(nameof(TestData))]
public void EnumeratorEnumeratesCharacters(InterningTestData.TestDatum datum)
{
using SpanBasedStringBuilder stringBuilder = MakeSpanBasedStringBuilder(datum);
int index = 0;
foreach (char ch in stringBuilder)
{
ch.ShouldBe(datum[index]);
index++;
}
}
[Theory]
[MemberData(nameof(TestData))]
public void EqualsReturnsExpectedValue(InterningTestData.TestDatum datum)
{
using var stringBuilder = MakeSpanBasedStringBuilder(datum);
InternableString internableString = new InternableString(stringBuilder);
internableString.Equals(string.Empty).ShouldBe(internableString.Length == 0);
string substr = datum.Fragments[0] ?? string.Empty;
internableString.Equals(substr).ShouldBe(substr.Length == internableString.Length);
if (datum.Fragments.Length > 1)
{
substr += datum.Fragments[1];
internableString.Equals(substr).ShouldBe(substr.Length == internableString.Length);
internableString.Equals(datum.ToString()).ShouldBeTrue();
}
internableString.Equals("Things").ShouldBeFalse();
}
[Fact]
public void ReferenceEqualsReturnsExpectedValue()
{
string str = "Test";
InternableString internableString = new InternableString(str);
internableString.ReferenceEquals(str).ShouldBeTrue();
internableString = new InternableString(new string(str.ToCharArray()));
internableString.ReferenceEquals(str).ShouldBeFalse();
}
[Theory]
[InlineData("012345678")] // odd number of characters
[InlineData("0123456789")] // even number of characters
public void GetHashCodeIsStableRegardlessOfSpanLength(string testString)
{
int hashCode = new InternableString(testString).GetHashCode();
// Chop the string into 2-3 parts and verify that the hash code is unchanged.
for (int i = 0; i < testString.Length - 1; i++)
{
for (int j = i + 1; j < testString.Length; j++)
{
using SpanBasedStringBuilder stringBuilder = new SpanBasedStringBuilder();
stringBuilder.Append(testString.Substring(0, i));
stringBuilder.Append(testString.Substring(i, j - i));
stringBuilder.Append(testString.Substring(j));
InternableString internableString = new InternableString(stringBuilder);
internableString.GetHashCode().ShouldBe(hashCode);
}
}
}
[Theory]
[MemberData(nameof(TestData))]
public void AppendAppendsString(InterningTestData.TestDatum datum)
{
using SpanBasedStringBuilder stringBuilder = MakeSpanBasedStringBuilder(datum, false);
new InternableString(stringBuilder).ExpensiveConvertToString().ShouldBe(datum.ToString());
}
[Theory]
[MemberData(nameof(TestData))]
public void AppendAppendsSubstring(InterningTestData.TestDatum datum)
{
using SpanBasedStringBuilder stringBuilder = MakeSpanBasedStringBuilder(datum, true);
new InternableString(stringBuilder).ExpensiveConvertToString().ShouldBe(datum.ToString());
}
#if !NET35_UNITTEST
[Theory]
[MemberData(nameof(TestDataForTrim))]
public void TrimStartRemovesLeadingWhiteSpace(InterningTestData.TestDatum datum)
{
using SpanBasedStringBuilder stringBuilder = MakeSpanBasedStringBuilder(datum);
stringBuilder.TrimStart();
new InternableString(stringBuilder).ExpensiveConvertToString().ShouldBe(datum.ToString().TrimStart());
}
[Theory]
[MemberData(nameof(TestDataForTrim))]
public void TrimEndRemovesTrailingWhiteSpace(InterningTestData.TestDatum datum)
{
using SpanBasedStringBuilder stringBuilder = MakeSpanBasedStringBuilder(datum);
stringBuilder.TrimEnd();
new InternableString(stringBuilder).ExpensiveConvertToString().ShouldBe(datum.ToString().TrimEnd());
}
[Theory]
[MemberData(nameof(TestDataForTrim))]
public void TrimRemovesLeadingAndTrailingWhiteSpace(InterningTestData.TestDatum datum)
{
using SpanBasedStringBuilder stringBuilder = MakeSpanBasedStringBuilder(datum);
stringBuilder.Trim();
new InternableString(stringBuilder).ExpensiveConvertToString().ShouldBe(datum.ToString().Trim());
}
#endif
[Theory]
[MemberData(nameof(TestData))]
public void ClearRemovesAllCharacters(InterningTestData.TestDatum datum)
{
using SpanBasedStringBuilder stringBuilder = MakeSpanBasedStringBuilder(datum);
stringBuilder.Clear();
stringBuilder.Length.ShouldBe(0);
stringBuilder.GetEnumerator().MoveNext().ShouldBeFalse();
}
}
}
|