mirror of
https://github.com/oliverbooth/X10D
synced 2024-11-22 23:58:48 +00:00
Move additional methods into child namespaces (#7)
This commit is contained in:
parent
efaf93594a
commit
30e925cdb0
106
X10D.Tests/src/Collections/ArrayTests.cs
Normal file
106
X10D.Tests/src/Collections/ArrayTests.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using X10D.Collections;
|
||||||
|
using X10D.Core;
|
||||||
|
|
||||||
|
namespace X10D.Tests.Collections;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class ArrayTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(1)]
|
||||||
|
[DataRow("f")]
|
||||||
|
[DataRow(true)]
|
||||||
|
public void AsArrayShouldGiveLength1(object o)
|
||||||
|
{
|
||||||
|
object[] array = o.AsArray()!;
|
||||||
|
Assert.IsNotNull(array);
|
||||||
|
Assert.IsTrue(array.Length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(1)]
|
||||||
|
[DataRow("f")]
|
||||||
|
[DataRow(true)]
|
||||||
|
public void AsArrayShouldContainObject(object o)
|
||||||
|
{
|
||||||
|
object[] array = o.AsArray()!;
|
||||||
|
Assert.IsNotNull(array);
|
||||||
|
Assert.AreEqual(o, array[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AsReadOnlyShouldBeReadOnly()
|
||||||
|
{
|
||||||
|
var array = new object[] {1, "f", true};
|
||||||
|
var readOnly = array.AsReadOnly();
|
||||||
|
Assert.IsNotNull(readOnly);
|
||||||
|
Assert.IsTrue(readOnly.Count == 3);
|
||||||
|
|
||||||
|
// ReSharper disable once ConvertTypeCheckToNullCheck
|
||||||
|
Assert.IsTrue(readOnly is IReadOnlyCollection<object>);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AsReadOnlyNullShouldThrow()
|
||||||
|
{
|
||||||
|
object[]? array = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(array!.AsReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow]
|
||||||
|
[DataRow(1)]
|
||||||
|
[DataRow(1, 2, 3)]
|
||||||
|
[DataRow(1, 2, 3, 4, 5)]
|
||||||
|
public void ClearShouldFillDefault(params int[] args)
|
||||||
|
{
|
||||||
|
args.Clear();
|
||||||
|
|
||||||
|
int[] clearedArray = Enumerable.Repeat(0, args.Length).ToArray();
|
||||||
|
CollectionAssert.AreEqual(clearedArray, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ClearNullShouldThrow()
|
||||||
|
{
|
||||||
|
int[]? array = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(array!.Clear);
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.Clear(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow]
|
||||||
|
[DataRow(1)]
|
||||||
|
[DataRow(1, 2, 3)]
|
||||||
|
[DataRow(1, 2, 3, 4, 5)]
|
||||||
|
public void FillShouldBeCorrect(params int[] args)
|
||||||
|
{
|
||||||
|
args.Fill(1);
|
||||||
|
|
||||||
|
int[] comparison = Enumerable.Repeat(1, args.Length).ToArray();
|
||||||
|
CollectionAssert.AreEqual(comparison, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void FillNullShouldThrow()
|
||||||
|
{
|
||||||
|
int[]? array = null;
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.Fill(0));
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => array!.Fill(0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(1)]
|
||||||
|
[DataRow(1, 2, 3)]
|
||||||
|
[DataRow(1, 2, 3, 4, 5)]
|
||||||
|
public void FillSlicedShouldBeCorrect(params int[] args)
|
||||||
|
{
|
||||||
|
int first = args[0];
|
||||||
|
args.Fill(1, 1, args.Length - 1);
|
||||||
|
|
||||||
|
int[] comparison = Enumerable.Repeat(1, args.Length - 1).ToArray();
|
||||||
|
Assert.AreEqual(first, args[0]);
|
||||||
|
CollectionAssert.AreEqual(comparison, args[1..]);
|
||||||
|
}
|
||||||
|
}
|
@ -1,60 +0,0 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using X10D.Core;
|
|
||||||
|
|
||||||
namespace X10D.Tests.Core;
|
|
||||||
|
|
||||||
[TestClass]
|
|
||||||
public class ArrayTests
|
|
||||||
{
|
|
||||||
[TestMethod]
|
|
||||||
[DataRow(1)]
|
|
||||||
[DataRow("f")]
|
|
||||||
[DataRow(true)]
|
|
||||||
public void AsArray(object o)
|
|
||||||
{
|
|
||||||
object[] array = o.AsArray();
|
|
||||||
Assert.IsNotNull(array);
|
|
||||||
Assert.IsTrue(array.Length == 1);
|
|
||||||
Assert.AreEqual(o, array[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[DataRow]
|
|
||||||
[DataRow(1)]
|
|
||||||
[DataRow(1, 2, 3)]
|
|
||||||
[DataRow(1, 2, 3, 4, 5)]
|
|
||||||
public void Clear(params int[] args)
|
|
||||||
{
|
|
||||||
args.Clear();
|
|
||||||
|
|
||||||
int[] comparison = Enumerable.Repeat(0, args.Length).ToArray();
|
|
||||||
CollectionAssert.AreEqual(args, comparison);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ClearNull()
|
|
||||||
{
|
|
||||||
int[]? array = null;
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(array!.Clear);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
[DataRow]
|
|
||||||
[DataRow(1)]
|
|
||||||
[DataRow(1, 2, 3)]
|
|
||||||
[DataRow(1, 2, 3, 4, 5)]
|
|
||||||
public void Fill(params int[] args)
|
|
||||||
{
|
|
||||||
args.Fill(1);
|
|
||||||
|
|
||||||
int[] comparison = Enumerable.Repeat(1, args.Length).ToArray();
|
|
||||||
CollectionAssert.AreEqual(args, comparison);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void FillNull()
|
|
||||||
{
|
|
||||||
int[]? array = null;
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => array!.Fill(0));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using X10D.Core;
|
using X10D.Core;
|
||||||
using X10D.Text;
|
|
||||||
|
|
||||||
namespace X10D.Tests.Core;
|
namespace X10D.Tests.Core;
|
||||||
|
|
||||||
|
@ -8,50 +8,6 @@ namespace X10D.Tests.Core;
|
|||||||
[TestClass]
|
[TestClass]
|
||||||
public class StringTests
|
public class StringTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.AsNullIfEmpty" />.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void AsNullIfEmpty()
|
|
||||||
{
|
|
||||||
const string sampleString = "Hello World";
|
|
||||||
const string whitespaceString = " ";
|
|
||||||
const string emptyString = "";
|
|
||||||
const string? nullString = null;
|
|
||||||
|
|
||||||
string sampleResult = sampleString.AsNullIfEmpty();
|
|
||||||
string whitespaceResult = whitespaceString.AsNullIfEmpty();
|
|
||||||
string emptyResult = emptyString.AsNullIfEmpty();
|
|
||||||
string? nullResult = nullString.AsNullIfEmpty();
|
|
||||||
|
|
||||||
Assert.AreEqual(sampleString, sampleResult);
|
|
||||||
Assert.AreEqual(whitespaceString, whitespaceResult);
|
|
||||||
Assert.AreEqual(nullString, emptyResult);
|
|
||||||
Assert.AreEqual(nullString, nullResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.AsNullIfWhiteSpace" />.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void AsNullIfWhiteSpace()
|
|
||||||
{
|
|
||||||
const string sampleString = "Hello World";
|
|
||||||
const string whitespaceString = " ";
|
|
||||||
const string emptyString = "";
|
|
||||||
const string? nullString = null;
|
|
||||||
|
|
||||||
string sampleResult = sampleString.AsNullIfWhiteSpace();
|
|
||||||
string whitespaceResult = whitespaceString.AsNullIfWhiteSpace();
|
|
||||||
string emptyResult = emptyString.AsNullIfWhiteSpace();
|
|
||||||
string? nullResult = nullString.AsNullIfWhiteSpace();
|
|
||||||
|
|
||||||
Assert.AreEqual(sampleString, sampleResult);
|
|
||||||
Assert.AreEqual(nullString, whitespaceResult);
|
|
||||||
Assert.AreEqual(nullString, emptyResult);
|
|
||||||
Assert.AreEqual(nullString, nullResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests <see cref="StringExtensions.Base64Decode" />.
|
/// Tests <see cref="StringExtensions.Base64Decode" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -81,78 +37,6 @@ public class StringTests
|
|||||||
Assert.AreEqual(expected, result);
|
Assert.AreEqual(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.IsLower" />.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void IsLower()
|
|
||||||
{
|
|
||||||
const string inputA = "Hello World";
|
|
||||||
const string inputB = "hello world";
|
|
||||||
const string? nullString = null;
|
|
||||||
|
|
||||||
bool resultA = inputA.IsLower();
|
|
||||||
bool resultB = inputB.IsLower();
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => nullString!.IsLower());
|
|
||||||
Assert.IsFalse(resultA);
|
|
||||||
Assert.IsTrue(resultB);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void IsPalindrome()
|
|
||||||
{
|
|
||||||
const string inputA = "Race car";
|
|
||||||
const string inputB = "Racecar";
|
|
||||||
const string inputC = "A man, a plan, a canal, panama";
|
|
||||||
const string inputD = "Jackdaws love my big sphinx of quartz";
|
|
||||||
const string inputE = "Y";
|
|
||||||
const string inputF = "1";
|
|
||||||
const string inputG = "";
|
|
||||||
|
|
||||||
Assert.IsTrue(inputA.IsPalindrome(), inputA);
|
|
||||||
Assert.IsTrue(inputB.IsPalindrome(), inputB);
|
|
||||||
Assert.IsTrue(inputC.IsPalindrome(), inputC);
|
|
||||||
Assert.IsFalse(inputD.IsPalindrome(), inputD);
|
|
||||||
Assert.IsTrue(inputE.IsPalindrome(), inputE);
|
|
||||||
Assert.IsTrue(inputF.IsPalindrome(), inputF);
|
|
||||||
Assert.IsFalse(inputG.IsPalindrome(), inputG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.IsUpper" />.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void IsUpper()
|
|
||||||
{
|
|
||||||
const string inputA = "Hello World";
|
|
||||||
const string inputB = "HELLO WORLD";
|
|
||||||
const string? nullString = null;
|
|
||||||
|
|
||||||
bool resultA = inputA.IsUpper();
|
|
||||||
bool resultB = inputB.IsUpper();
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => nullString!.IsUpper());
|
|
||||||
Assert.IsFalse(resultA);
|
|
||||||
Assert.IsTrue(resultB);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.Shuffled(string, Random)" />.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void Shuffled()
|
|
||||||
{
|
|
||||||
const string input = "Hello World";
|
|
||||||
const string expected = " oHlldrWoel";
|
|
||||||
var random = new Random(1);
|
|
||||||
|
|
||||||
string result = input.Shuffled(random);
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.Shuffled());
|
|
||||||
Assert.AreEqual(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests <see cref="StringExtensions.Randomize" />.
|
/// Tests <see cref="StringExtensions.Randomize" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -170,66 +54,4 @@ public class StringTests
|
|||||||
Assert.AreEqual(string.Empty, string.Empty.Randomize(0));
|
Assert.AreEqual(string.Empty, string.Empty.Randomize(0));
|
||||||
Assert.AreEqual(expected, result);
|
Assert.AreEqual(expected, result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.Repeat" />.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void Repeat()
|
|
||||||
{
|
|
||||||
const string input = "Hello World";
|
|
||||||
const string expected = "Hello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello World";
|
|
||||||
const int repeatCount = 8;
|
|
||||||
|
|
||||||
string result = input.Repeat(repeatCount);
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.Repeat(repeatCount));
|
|
||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() => input.Repeat(-1));
|
|
||||||
Assert.AreEqual(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.Repeat" />.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void Reverse()
|
|
||||||
{
|
|
||||||
const string input = "Hello World";
|
|
||||||
const string expected = "dlroW olleH";
|
|
||||||
|
|
||||||
string result = input.Reverse();
|
|
||||||
|
|
||||||
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.Reverse());
|
|
||||||
Assert.AreEqual(string.Empty.Reverse(), string.Empty);
|
|
||||||
Assert.AreEqual(" ".Reverse(), " ");
|
|
||||||
Assert.AreEqual(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests <see cref="StringExtensions.WithEmptyAlternative" /> and
|
|
||||||
/// <see cref="StringExtensions.WithWhiteSpaceAlternative"/>.
|
|
||||||
/// </summary>
|
|
||||||
[TestMethod]
|
|
||||||
public void WithAlternative()
|
|
||||||
{
|
|
||||||
const string inputA = "Hello World";
|
|
||||||
const string inputB = " ";
|
|
||||||
const string inputC = "";
|
|
||||||
const string? inputD = null;
|
|
||||||
const string alternative = "ALTERNATIVE";
|
|
||||||
|
|
||||||
string resultA = inputA.WithEmptyAlternative(alternative);
|
|
||||||
string resultB = inputB.WithEmptyAlternative(alternative);
|
|
||||||
string resultBWithWhitespace = inputB.WithWhiteSpaceAlternative(alternative);
|
|
||||||
string resultC = inputC.WithEmptyAlternative(alternative);
|
|
||||||
string resultD = inputD.WithEmptyAlternative(alternative);
|
|
||||||
|
|
||||||
Assert.AreEqual(resultA, inputA);
|
|
||||||
Assert.AreEqual(resultB, inputB);
|
|
||||||
Assert.AreEqual(resultBWithWhitespace, alternative);
|
|
||||||
Assert.AreEqual(resultC, alternative);
|
|
||||||
Assert.AreEqual(resultD, alternative);
|
|
||||||
Assert.AreEqual(alternative, ((string?)null).WithEmptyAlternative(alternative));
|
|
||||||
Assert.AreEqual(alternative, ((string?)null).WithWhiteSpaceAlternative(alternative));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -16,7 +16,7 @@ public class RuneTests
|
|||||||
|
|
||||||
Assert.AreEqual(expected, actual);
|
Assert.AreEqual(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RepeatOneCountShouldBeLength1String()
|
public void RepeatOneCountShouldBeLength1String()
|
||||||
{
|
{
|
||||||
@ -24,13 +24,13 @@ public class RuneTests
|
|||||||
Assert.AreEqual(1, repeated.Length);
|
Assert.AreEqual(1, repeated.Length);
|
||||||
Assert.AreEqual("a", repeated);
|
Assert.AreEqual("a", repeated);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RepeatZeroCountShouldBeEmpty()
|
public void RepeatZeroCountShouldBeEmpty()
|
||||||
{
|
{
|
||||||
Assert.AreEqual(string.Empty, new Rune('a').Repeat(0));
|
Assert.AreEqual(string.Empty, new Rune('a').Repeat(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RepeatNegativeCountShouldThrow()
|
public void RepeatNegativeCountShouldThrow()
|
||||||
{
|
{
|
||||||
|
@ -7,10 +7,42 @@ namespace X10D.Tests.Text;
|
|||||||
[TestClass]
|
[TestClass]
|
||||||
public class StringTests
|
public class StringTests
|
||||||
{
|
{
|
||||||
private struct SampleStructure
|
[TestMethod]
|
||||||
|
public void AsNullIfEmptyShouldBeCorrect()
|
||||||
{
|
{
|
||||||
[JsonPropertyName("values")]
|
const string sampleString = "Hello World";
|
||||||
public int[] Values { get; set; }
|
const string whitespaceString = " ";
|
||||||
|
const string emptyString = "";
|
||||||
|
const string? nullString = null;
|
||||||
|
|
||||||
|
string sampleResult = sampleString.AsNullIfEmpty();
|
||||||
|
string whitespaceResult = whitespaceString.AsNullIfEmpty();
|
||||||
|
string emptyResult = emptyString.AsNullIfEmpty();
|
||||||
|
string? nullResult = nullString.AsNullIfEmpty();
|
||||||
|
|
||||||
|
Assert.AreEqual(sampleString, sampleResult);
|
||||||
|
Assert.AreEqual(whitespaceString, whitespaceResult);
|
||||||
|
Assert.AreEqual(nullString, emptyResult);
|
||||||
|
Assert.AreEqual(nullString, nullResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AsNullIfWhiteSpaceShouldBeCorrect()
|
||||||
|
{
|
||||||
|
const string sampleString = "Hello World";
|
||||||
|
const string whitespaceString = " ";
|
||||||
|
const string emptyString = "";
|
||||||
|
const string? nullString = null;
|
||||||
|
|
||||||
|
string sampleResult = sampleString.AsNullIfWhiteSpace();
|
||||||
|
string whitespaceResult = whitespaceString.AsNullIfWhiteSpace();
|
||||||
|
string emptyResult = emptyString.AsNullIfWhiteSpace();
|
||||||
|
string? nullResult = nullString.AsNullIfWhiteSpace();
|
||||||
|
|
||||||
|
Assert.AreEqual(sampleString, sampleResult);
|
||||||
|
Assert.AreEqual(nullString, whitespaceResult);
|
||||||
|
Assert.AreEqual(nullString, emptyResult);
|
||||||
|
Assert.AreEqual(nullString, nullResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@ -26,4 +58,174 @@ public class StringTests
|
|||||||
Assert.AreEqual(2, target.Values[1]);
|
Assert.AreEqual(2, target.Values[1]);
|
||||||
Assert.AreEqual(3, target.Values[2]);
|
Assert.AreEqual(3, target.Values[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsLowerShouldBeCorrect()
|
||||||
|
{
|
||||||
|
Assert.IsTrue("hello world".IsLower());
|
||||||
|
Assert.IsFalse("HELLO WORLD".IsLower());
|
||||||
|
Assert.IsFalse("Hello World".IsLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsLowerNullShouldThrow()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.IsLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsPalindromeShouldBeCorrect()
|
||||||
|
{
|
||||||
|
const string inputA = "Race car";
|
||||||
|
const string inputB = "Racecar";
|
||||||
|
const string inputC = "A man, a plan, a canal, panama";
|
||||||
|
const string inputD = "Jackdaws love my big sphinx of quartz";
|
||||||
|
const string inputE = "Y";
|
||||||
|
const string inputF = "1";
|
||||||
|
|
||||||
|
Assert.IsTrue(inputA.IsPalindrome(), inputA);
|
||||||
|
Assert.IsTrue(inputB.IsPalindrome(), inputB);
|
||||||
|
Assert.IsTrue(inputC.IsPalindrome(), inputC);
|
||||||
|
Assert.IsFalse(inputD.IsPalindrome(), inputD);
|
||||||
|
Assert.IsTrue(inputE.IsPalindrome(), inputE);
|
||||||
|
Assert.IsTrue(inputF.IsPalindrome(), inputF);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsPalindromeEmptyShouldBeFalse()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(string.Empty.IsPalindrome());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsPalindromeNullShouldThrow()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.IsPalindrome());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsUpperShouldBeCorrect()
|
||||||
|
{
|
||||||
|
Assert.IsTrue("HELLO WORLD".IsUpper());
|
||||||
|
Assert.IsFalse("hello world".IsUpper());
|
||||||
|
Assert.IsFalse("Hello World".IsUpper());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IsUpperNullShouldThrow()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.IsUpper());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RepeatShouldBeCorrect()
|
||||||
|
{
|
||||||
|
const string expected = "aaaaaaaaaa";
|
||||||
|
string actual = "a".Repeat(10);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RepeatOneCountShouldBeLength1String()
|
||||||
|
{
|
||||||
|
string repeated = "a".Repeat(1);
|
||||||
|
Assert.AreEqual(1, repeated.Length);
|
||||||
|
Assert.AreEqual("a", repeated);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RepeatZeroCountShouldBeEmpty()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(string.Empty, "a".Repeat(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RepeatNegativeCountShouldThrow()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => "a".Repeat(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RepeatNullShouldThrow()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.Repeat(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReverseShouldBeCorrect()
|
||||||
|
{
|
||||||
|
const string input = "Hello World";
|
||||||
|
const string expected = "dlroW olleH";
|
||||||
|
|
||||||
|
string result = input.Reverse();
|
||||||
|
|
||||||
|
Assert.AreEqual(string.Empty.Reverse(), string.Empty);
|
||||||
|
Assert.AreEqual(" ".Reverse(), " ");
|
||||||
|
Assert.AreEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ReverseNullShouldThrow()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.Reverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ShuffleShouldReorder()
|
||||||
|
{
|
||||||
|
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
string shuffled = alphabet;
|
||||||
|
|
||||||
|
Assert.AreEqual(alphabet, shuffled);
|
||||||
|
|
||||||
|
shuffled = alphabet.Shuffled();
|
||||||
|
|
||||||
|
Assert.AreNotEqual(alphabet, shuffled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NullShuffleShouldThrow()
|
||||||
|
{
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null)!.Shuffled());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WithEmptyAlternativeShouldBeCorrect()
|
||||||
|
{
|
||||||
|
const string inputA = "Hello World";
|
||||||
|
const string inputB = " ";
|
||||||
|
const string inputC = "";
|
||||||
|
const string? inputD = null;
|
||||||
|
const string alternative = "ALTERNATIVE";
|
||||||
|
|
||||||
|
string resultA = inputA.WithEmptyAlternative(alternative);
|
||||||
|
string resultB = inputB.WithEmptyAlternative(alternative);
|
||||||
|
string resultC = inputC.WithEmptyAlternative(alternative);
|
||||||
|
string resultD = inputD.WithEmptyAlternative(alternative);
|
||||||
|
|
||||||
|
Assert.AreEqual(resultA, inputA);
|
||||||
|
Assert.AreEqual(resultB, inputB);
|
||||||
|
Assert.AreEqual(resultC, alternative);
|
||||||
|
Assert.AreEqual(resultD, alternative);
|
||||||
|
Assert.AreEqual(alternative, ((string?)null).WithEmptyAlternative(alternative));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WithWhiteSpaceAlternativeShouldBeCorrect()
|
||||||
|
{
|
||||||
|
const string input = " ";
|
||||||
|
const string alternative = "ALTERNATIVE";
|
||||||
|
|
||||||
|
string result = input.WithWhiteSpaceAlternative(alternative);
|
||||||
|
|
||||||
|
Assert.AreEqual(result, alternative);
|
||||||
|
Assert.AreEqual(alternative, ((string?)null).WithWhiteSpaceAlternative(alternative));
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct SampleStructure
|
||||||
|
{
|
||||||
|
[JsonPropertyName("values")]
|
||||||
|
public int[] Values { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace X10D;
|
namespace X10D.Collections;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extension methods for <see cref="Array" />.
|
/// Extension methods for <see cref="Array" />.
|
@ -1,6 +1,4 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using X10D.Collections;
|
|
||||||
|
|
||||||
namespace X10D;
|
namespace X10D;
|
||||||
|
|
||||||
@ -9,35 +7,6 @@ namespace X10D;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Normalizes a string which may be either <see langword="null" /> or empty to <see langword="null" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to normalize.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <see langword="null" /> if <paramref name="value" /> is <see langword="null" /> or empty; otherwise,
|
|
||||||
/// <paramref name="value" />.
|
|
||||||
/// </returns>
|
|
||||||
[return: NotNullIfNotNull("value")]
|
|
||||||
public static string? AsNullIfEmpty(this string? value)
|
|
||||||
{
|
|
||||||
return value.WithEmptyAlternative(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Normalizes a string which may be either <see langword="null" />, empty, or consisting of only whitespace, to
|
|
||||||
/// <see langword="null" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to normalize.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <see langword="null" /> if <paramref name="value" /> is <see langword="null" />, empty, or consists of only
|
|
||||||
/// whitespace; otherwise, <paramref name="value" />.
|
|
||||||
/// </returns>
|
|
||||||
[return: NotNullIfNotNull("value")]
|
|
||||||
public static string? AsNullIfWhiteSpace(this string? value)
|
|
||||||
{
|
|
||||||
return value.WithWhiteSpaceAlternative(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the specified string, which encodes binary data as base-64 digits, to an equivalent plain text string.
|
/// Converts the specified string, which encodes binary data as base-64 digits, to an equivalent plain text string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -188,117 +157,6 @@ public static class StringExtensions
|
|||||||
return encoding.GetBytes(value);
|
return encoding.GetBytes(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if all alpha characters in this string are considered lowercase.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The input string.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// Returns <see langword="true" /> if all alpha characters are lowercase, <see langword="false" />
|
|
||||||
/// otherwise.
|
|
||||||
/// </returns>
|
|
||||||
public static bool IsLower(this string value)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var index = 0; index < value.Length; index++)
|
|
||||||
{
|
|
||||||
if (!char.IsLetter(value[index]))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!char.IsLower(value[index]))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the current string is considered palindromic; that is, the letters within the string are the
|
|
||||||
/// same when reversed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to check.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <see langword="true" /> if <paramref name="value" /> is considered a palindromic string; otherwise,
|
|
||||||
/// <see langword="false" />.
|
|
||||||
/// </returns>
|
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="value" /> is <see langword="null" />.</exception>
|
|
||||||
public static bool IsPalindrome(this string value)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
|
||||||
{
|
|
||||||
// empty string is not palindromic
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0, endIndex = value.Length - 1; index < value.Length; index++, endIndex--)
|
|
||||||
{
|
|
||||||
Rune startRune = new Rune(value[index]);
|
|
||||||
Rune endRune = new Rune(value[endIndex]);
|
|
||||||
|
|
||||||
if (!Rune.IsLetter(startRune) && !Rune.IsNumber(startRune))
|
|
||||||
{
|
|
||||||
endIndex++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Rune.IsLetter(endRune) && !Rune.IsNumber(endRune))
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Rune.ToUpperInvariant(startRune) != Rune.ToUpperInvariant(endRune))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if all alpha characters in this string are considered uppercase.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The input string.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// Returns <see langword="true" /> if all alpha characters are uppercase, <see langword="false" />
|
|
||||||
/// otherwise.
|
|
||||||
/// </returns>
|
|
||||||
public static bool IsUpper(this string value)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var index = 0; index < value.Length; index++)
|
|
||||||
{
|
|
||||||
if (!char.IsLetter(value[index]))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!char.IsUpper(value[index]))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a new string of a specified length by randomly selecting characters from the current string.
|
/// Returns a new string of a specified length by randomly selecting characters from the current string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -342,102 +200,6 @@ public static class StringExtensions
|
|||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Repeats a string a specified number of times.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The string to repeat.</param>
|
|
||||||
/// <param name="count">The repeat count.</param>
|
|
||||||
/// <returns>A string containing <paramref name="value" /> repeated <paramref name="count" /> times.
|
|
||||||
/// </returns>
|
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="value" /> is <see langword="null" />.</exception>
|
|
||||||
public static string Repeat(this string value, int count)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(count), ExceptionMessages.CountMustBeGreaterThanOrEqualTo0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder = new StringBuilder(value.Length * count);
|
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
builder.Append(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reverses the current string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The string to reverse.</param>
|
|
||||||
/// <returns>A <see cref="string" /> whose characters are that of <paramref name="value" /> in reverse order.</returns>
|
|
||||||
public static string Reverse(this string value)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.Length < 2)
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
char* array = stackalloc char[value.Length];
|
|
||||||
|
|
||||||
for (var index = 0; index < value.Length; index++)
|
|
||||||
{
|
|
||||||
array[index] = value[value.Length - index - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new string(array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shuffles the characters in the string using the <see cref="Random.Shared" /> instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The string to shuffle.</param>
|
|
||||||
/// <returns>A new <see cref="string" /> containing the characters in <paramref name="value" />, rearranged.</returns>
|
|
||||||
public static string Shuffled(this string value)
|
|
||||||
{
|
|
||||||
return value.Shuffled(Random.Shared);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shuffles the characters in the string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The string to shuffle.</param>
|
|
||||||
/// <param name="random">The <see cref="System.Random" /> instance.</param>
|
|
||||||
/// <returns>A new <see cref="string" /> containing the characters in <paramref name="value" />, rearranged.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException">
|
|
||||||
/// <para><paramref name="value" /> is <see langword="null" />.</para>
|
|
||||||
/// -or-
|
|
||||||
/// <para><paramref name="random" /> is <see langword="null" />.</para>
|
|
||||||
/// </exception>
|
|
||||||
public static string Shuffled(this string value, Random random)
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (random is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(random));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new string(value.ToCharArray().Shuffled(random).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Splits the <see cref="string" /> into chunks that are no greater than <paramref name="chunkSize" /> in length.
|
/// Splits the <see cref="string" /> into chunks that are no greater than <paramref name="chunkSize" /> in length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -478,35 +240,4 @@ public static class StringExtensions
|
|||||||
? result
|
? result
|
||||||
: default;
|
: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Normalizes a string which may be either <see langword="null" /> or empty to a specified alternative.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to normalize.</param>
|
|
||||||
/// <param name="alternative">The alternative string.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <paramref name="alternative" /> if <paramref name="value" /> is <see langword="null" /> or empty; otherwise,
|
|
||||||
/// <paramref name="value" />.
|
|
||||||
/// </returns>
|
|
||||||
[return: NotNullIfNotNull("alternative")]
|
|
||||||
public static string? WithEmptyAlternative(this string? value, string? alternative)
|
|
||||||
{
|
|
||||||
return string.IsNullOrEmpty(value) ? alternative : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Normalizes a string which may be either <see langword="null" />, empty, or consisting of only whitespace, to a
|
|
||||||
/// specified alternative.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to normalize.</param>
|
|
||||||
/// <param name="alternative">The alternative string.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <paramref name="alternative" /> if <paramref name="value" /> is <see langword="null" />, empty, or consists of only
|
|
||||||
/// whitespace; otherwise, <paramref name="value" />.
|
|
||||||
/// </returns>
|
|
||||||
[return: NotNullIfNotNull("alternative")]
|
|
||||||
public static string? WithWhiteSpaceAlternative(this string? value, string? alternative)
|
|
||||||
{
|
|
||||||
return string.IsNullOrWhiteSpace(value) ? alternative : value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
namespace X10D.Text;
|
namespace X10D.Text;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extension methods for <see cref="char" />.
|
/// Text-related extension methods for <see cref="char" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class CharExtensions
|
public static class CharExtensions
|
||||||
{
|
{
|
||||||
@ -15,21 +15,12 @@ public static class CharExtensions
|
|||||||
/// </returns>
|
/// </returns>
|
||||||
public static string Repeat(this char value, int count)
|
public static string Repeat(this char value, int count)
|
||||||
{
|
{
|
||||||
if (count < 0)
|
return count switch
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(count), ExceptionMessages.CountMustBeGreaterThanOrEqualTo0);
|
< 0 => throw new ArgumentOutOfRangeException(nameof(count), ExceptionMessages.CountMustBeGreaterThanOrEqualTo0),
|
||||||
}
|
0 => string.Empty,
|
||||||
|
1 => value.ToString(),
|
||||||
if (count == 0)
|
_ => new string(value, count)
|
||||||
{
|
};
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 1)
|
|
||||||
{
|
|
||||||
return value.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new string(value, count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace X10D.Text;
|
namespace X10D.Text;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extension methods for <see cref="Rune" />.
|
/// Text-related extension methods for <see cref="Rune" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class RuneExtensions
|
public static class RuneExtensions
|
||||||
{
|
{
|
||||||
@ -17,19 +17,14 @@ public static class RuneExtensions
|
|||||||
/// </returns>
|
/// </returns>
|
||||||
public static string Repeat(this Rune value, int count)
|
public static string Repeat(this Rune value, int count)
|
||||||
{
|
{
|
||||||
if (count < 0)
|
switch (count)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(count), ExceptionMessages.CountMustBeGreaterThanOrEqualTo0);
|
case < 0:
|
||||||
}
|
throw new ArgumentOutOfRangeException(nameof(count), ExceptionMessages.CountMustBeGreaterThanOrEqualTo0);
|
||||||
|
case 0:
|
||||||
if (count == 0)
|
return string.Empty;
|
||||||
{
|
case 1:
|
||||||
return string.Empty;
|
return value.ToString();
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 1)
|
|
||||||
{
|
|
||||||
return value.ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int utf8SequenceLength = value.Utf8SequenceLength;
|
int utf8SequenceLength = value.Utf8SequenceLength;
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using X10D.Collections;
|
||||||
|
|
||||||
namespace X10D.Text;
|
namespace X10D.Text;
|
||||||
|
|
||||||
@ -7,6 +10,35 @@ namespace X10D.Text;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a string which may be either <see langword="null" /> or empty to <see langword="null" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to normalize.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="null" /> if <paramref name="value" /> is <see langword="null" /> or empty; otherwise,
|
||||||
|
/// <paramref name="value" />.
|
||||||
|
/// </returns>
|
||||||
|
[return: NotNullIfNotNull("value")]
|
||||||
|
public static string? AsNullIfEmpty(this string? value)
|
||||||
|
{
|
||||||
|
return value.WithEmptyAlternative(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a string which may be either <see langword="null" />, empty, or consisting of only whitespace, to
|
||||||
|
/// <see langword="null" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to normalize.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="null" /> if <paramref name="value" /> is <see langword="null" />, empty, or consists of only
|
||||||
|
/// whitespace; otherwise, <paramref name="value" />.
|
||||||
|
/// </returns>
|
||||||
|
[return: NotNullIfNotNull("value")]
|
||||||
|
public static string? AsNullIfWhiteSpace(this string? value)
|
||||||
|
{
|
||||||
|
return value.WithWhiteSpaceAlternative(null);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an object from the specified JSON string.
|
/// Returns an object from the specified JSON string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -20,4 +52,236 @@ public static class StringExtensions
|
|||||||
{
|
{
|
||||||
return JsonSerializer.Deserialize<T>(value, options);
|
return JsonSerializer.Deserialize<T>(value, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if all alpha characters in this string are considered lowercase.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input string.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Returns <see langword="true" /> if all alpha characters are lowercase, <see langword="false" />
|
||||||
|
/// otherwise.
|
||||||
|
/// </returns>
|
||||||
|
public static bool IsLower(this string value)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var index = 0; index < value.Length; index++)
|
||||||
|
{
|
||||||
|
var rune = new Rune(value[index]);
|
||||||
|
|
||||||
|
if (!Rune.IsLetter(rune))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Rune.IsLower(rune))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the current string is considered palindromic; that is, the letters within the string are the
|
||||||
|
/// same when reversed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to check.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true" /> if <paramref name="value" /> is considered a palindromic string; otherwise,
|
||||||
|
/// <see langword="false" />.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="value" /> is <see langword="null" />.</exception>
|
||||||
|
public static bool IsPalindrome(this string value)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
// empty string is not palindromic
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = 0, endIndex = value.Length - 1; index < value.Length; index++, endIndex--)
|
||||||
|
{
|
||||||
|
Rune startRune = new Rune(value[index]);
|
||||||
|
Rune endRune = new Rune(value[endIndex]);
|
||||||
|
|
||||||
|
if (!Rune.IsLetter(startRune) && !Rune.IsNumber(startRune))
|
||||||
|
{
|
||||||
|
endIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Rune.IsLetter(endRune) && !Rune.IsNumber(endRune))
|
||||||
|
{
|
||||||
|
index--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Rune.ToUpperInvariant(startRune) != Rune.ToUpperInvariant(endRune))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if all alpha characters in this string are considered uppercase.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input string.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Returns <see langword="true" /> if all alpha characters are uppercase, <see langword="false" />
|
||||||
|
/// otherwise.
|
||||||
|
/// </returns>
|
||||||
|
public static bool IsUpper(this string value)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var index = 0; index < value.Length; index++)
|
||||||
|
{
|
||||||
|
var rune = new Rune(value[index]);
|
||||||
|
|
||||||
|
if (!Rune.IsLetter(rune))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Rune.IsUpper(rune))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Repeats a string a specified number of times.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The string to repeat.</param>
|
||||||
|
/// <param name="count">The repeat count.</param>
|
||||||
|
/// <returns>A string containing <paramref name="value" /> repeated <paramref name="count" /> times.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="value" /> is <see langword="null" />.</exception>
|
||||||
|
public static string Repeat(this string value, int count)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (count)
|
||||||
|
{
|
||||||
|
case < 0:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(count), ExceptionMessages.CountMustBeGreaterThanOrEqualTo0);
|
||||||
|
case 0:
|
||||||
|
return string.Empty;
|
||||||
|
case 1:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder(value.Length * count);
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
builder.Append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reverses the current string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The string to reverse.</param>
|
||||||
|
/// <returns>A <see cref="string" /> whose characters are that of <paramref name="value" /> in reverse order.</returns>
|
||||||
|
public static string Reverse(this string value)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Length < 2)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<char> span = stackalloc char[value.Length];
|
||||||
|
|
||||||
|
for (var index = 0; index < value.Length; index++)
|
||||||
|
{
|
||||||
|
span[index] = value[value.Length - index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shuffles the characters in the string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The string to shuffle.</param>
|
||||||
|
/// <param name="random">
|
||||||
|
/// The <see cref="System.Random" /> instance to use for the shuffling. If <see langword="null" /> is specified,
|
||||||
|
/// <see cref="System.Random.Shared" /> is used.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A new <see cref="string" /> containing the characters in <paramref name="value" />, rearranged.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="value" /> is <see langword="null" />.</exception>
|
||||||
|
public static string Shuffled(this string value, Random? random = null)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
random ??= Random.Shared;
|
||||||
|
|
||||||
|
char[] array = value.ToCharArray();
|
||||||
|
array.Shuffle(random);
|
||||||
|
return new string(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a string which may be either <see langword="null" /> or empty to a specified alternative.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to normalize.</param>
|
||||||
|
/// <param name="alternative">The alternative string.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <paramref name="alternative" /> if <paramref name="value" /> is <see langword="null" /> or empty; otherwise,
|
||||||
|
/// <paramref name="value" />.
|
||||||
|
/// </returns>
|
||||||
|
[return: NotNullIfNotNull("alternative")]
|
||||||
|
public static string? WithEmptyAlternative(this string? value, string? alternative)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(value) ? alternative : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normalizes a string which may be either <see langword="null" />, empty, or consisting of only whitespace, to a
|
||||||
|
/// specified alternative.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to normalize.</param>
|
||||||
|
/// <param name="alternative">The alternative string.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <paramref name="alternative" /> if <paramref name="value" /> is <see langword="null" />, empty, or consists of only
|
||||||
|
/// whitespace; otherwise, <paramref name="value" />.
|
||||||
|
/// </returns>
|
||||||
|
[return: NotNullIfNotNull("alternative")]
|
||||||
|
public static string? WithWhiteSpaceAlternative(this string? value, string? alternative)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? alternative : value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user