Skip to content

Commit 0d87fbc

Browse files
committed
Added simple builder for making UStrings. Added the Split method on UString. Added some convenience operators for UCodepoint.
1 parent 7a5cbcf commit 0d87fbc

8 files changed

Lines changed: 525 additions & 6 deletions

File tree

UnicodeHelper.Tests/UCodepointTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Globalization;
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Globalization;
23

34
namespace UnicodeHelper
45
{
@@ -645,6 +646,7 @@ public void GetNumericValue(UCodepoint uc, double expectedResult)
645646
}
646647

647648
[TestMethod]
649+
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
648650
public void GetNumericValue_CompareWithDotNet()
649651
{
650652
for (char c = '\u0000'; c < 0xFFFF; c++)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
namespace UnicodeHelper
2+
{
3+
[TestClass]
4+
public class UStringBuilderTests
5+
{
6+
#region Append (UCodepoint) tests
7+
public static IEnumerable<object?[]> AppendUCodepointTestData =>
8+
[
9+
[" ", " ", " "],
10+
["a", "a"],
11+
["\U00010570\U00010597", "\U00010570", "\U00010597"], // VITHKUQI letters
12+
["😁🤔😮", "😁", "🤔", "😮"]
13+
];
14+
15+
[TestMethod]
16+
[DynamicData(nameof(AppendUCodepointTestData))]
17+
public void Append_UCodepoint(string expectedResult, params string[] parts)
18+
{
19+
UStringBuilder usb = new UStringBuilder();
20+
foreach (string part in parts)
21+
usb.Append(UCodepoint.ReadFromStr(part, 0));
22+
23+
Assert.AreEqual(new UString(expectedResult), usb.ToUString());
24+
}
25+
#endregion
26+
27+
#region Append (UString) tests
28+
public static IEnumerable<object?[]> AppendUStringTestData =>
29+
[
30+
["", null],
31+
["", ""],
32+
["This is a test!", "This", " is a ", "test!"],
33+
["😁🤔😮", "😁", "🤔😮"],
34+
["This is a lot of text that will require a larger capacity. " +
35+
"The capacity should increase multiple times to accomodate this long string!" +
36+
"This is the end!",
37+
"This is a lot of text that will require a larger capacity. " +
38+
"The capacity should increase multiple times to accomodate this long string!",
39+
"This is the end!"]
40+
];
41+
42+
[TestMethod]
43+
[DynamicData(nameof(AppendUStringTestData))]
44+
public void Append_UString(string expectedResult, params string?[] parts)
45+
{
46+
UStringBuilder usb = new UStringBuilder();
47+
foreach (string? part in parts)
48+
usb.Append(part != null ? new UString(part) : null);
49+
50+
Assert.AreEqual(new UString(expectedResult), usb.ToUString());
51+
}
52+
#endregion
53+
54+
#region Append (.Net string) tests
55+
public static IEnumerable<object?[]> AppendStringTestData =>
56+
[
57+
["", null],
58+
["", ""],
59+
["This is a test!", "This", " is a ", "test!"],
60+
["😁🤔😮", "😁", "🤔😮"],
61+
["This is a lot of text that will require a larger capacity. " +
62+
"The capacity should increase multiple times to accomodate this long string!" +
63+
"This is the end!",
64+
"This is a lot of text that will require a larger capacity. " +
65+
"The capacity should increase multiple times to accomodate this long string!",
66+
"This is the end!"]
67+
];
68+
69+
[TestMethod]
70+
[DynamicData(nameof(AppendStringTestData))]
71+
public void Append_String(string expectedResult, params string?[] parts)
72+
{
73+
UStringBuilder usb = new UStringBuilder();
74+
foreach (string? part in parts)
75+
usb.Append(part);
76+
77+
Assert.AreEqual(new UString(expectedResult), usb.ToUString());
78+
}
79+
#endregion
80+
}
81+
}

UnicodeHelper.Tests/UStringTests.cs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@ public void Constructor(string testString, params string[] expectedCodepoints)
3131
}
3232
#endregion
3333

34+
#region CharLength tests
35+
private static IEnumerable<object[]> CharLengthTestData =>
36+
[
37+
["test", 4],
38+
["", 0],
39+
["This is\r\na test!", 16],
40+
["العربية", 7],
41+
["😁🤔😮", 6],
42+
["test😮", 6],
43+
];
44+
45+
[TestMethod]
46+
[DynamicData(nameof(CharLengthTestData))]
47+
public void CharLength(string str, int expectedResult)
48+
{
49+
UString us = new(str);
50+
Assert.AreEqual(expectedResult, us.CharLength);
51+
52+
// Test making sure that a substring results in the correct result
53+
us = CreateTestSubstring(str);
54+
Assert.AreEqual(expectedResult, us.CharLength);
55+
}
56+
#endregion
57+
3458
#region Equals tests
3559
private static IEnumerable<object[]> EqualsTestData =>
3660
[
@@ -542,6 +566,79 @@ public void Concat_StringList(string?[] strings, string expectedResults)
542566
Assert.AreEqual(UString.Concat(strings.Select(CreateTestSubstring).ToArray()), expectedUs);
543567
}
544568
#endregion
569+
570+
#region Split tests
571+
private static IEnumerable<object?[]> SplitExceptionTestData =>
572+
[
573+
["bla", null, 1, typeof(ArgumentException)],
574+
["bla", Array.Empty<UCodepoint>(), 1, typeof(ArgumentException)],
575+
["bla", new UCodepoint[] { ' ' }, -1, typeof(ArgumentOutOfRangeException)],
576+
["bla", new UCodepoint[] { ' ' }, 0, typeof(ArgumentOutOfRangeException)],
577+
];
578+
579+
[TestMethod]
580+
[DynamicData(nameof(SplitExceptionTestData))]
581+
public void Split_InvalidParameters(string testString, UCodepoint[]? separators, int maxCount,
582+
Type expectedExceptionType)
583+
{
584+
UString us = new(testString);
585+
Assert.That.ThrowsException(expectedExceptionType, () => us.Split(separators, maxCount));
586+
}
587+
588+
private static IEnumerable<object[]> SplitTestData =>
589+
[
590+
["", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "" }],
591+
["", new UCodepoint[] { ' ' }, 1, new[] { "" }],
592+
["This is a test!", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "This", "is", "a", "test!" }],
593+
["This is a test!", new UCodepoint[] { ' ' }, 2, new[] { "This", "is a test!" }],
594+
[" This is a test! ", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "", "This", "", "is", "a", "test!", "", "" }],
595+
["This is\r\na test!", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "This", "is\r\na", "test!" }],
596+
["This is\r\na test!", new UCodepoint[] { ' ', '\r', '\n' }, int.MaxValue, new[] { "This", "is", "", "a", "test!" }],
597+
["العربية", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "العربية" }],
598+
["😁🤔😮", new[] { UCodepoint.ReadFromStr("🤔", 0) }, int.MaxValue, new[] { "😁", "😮" }],
599+
];
600+
601+
[TestMethod]
602+
[DynamicData(nameof(SplitTestData))]
603+
public void Split(string testString, UCodepoint[]? separators, int maxCount, string[] expectedResults)
604+
{
605+
UString us = new(testString);
606+
UString[] expectedUss = expectedResults.Select(er => new UString(er)).ToArray();
607+
608+
Assert.That.SequenceEqual(expectedUss, us.Split(separators, maxCount));
609+
610+
// Test making sure that a substring results in the correct result
611+
us = CreateTestSubstring(testString);
612+
Assert.That.SequenceEqual(expectedUss, us.Split(separators, maxCount));
613+
}
614+
615+
private static IEnumerable<object[]> SplitIgnoreEmptyTestData =>
616+
[
617+
["", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "" }],
618+
["", new UCodepoint[] { ' ' }, 1, new[] { "" }],
619+
["This is a test!", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "This", "is", "a", "test!" }],
620+
["This is a test!", new UCodepoint[] { ' ' }, 2, new[] { "This", "is a test!" }],
621+
[" This is a test! ", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "This", "is", "a", "test!" }],
622+
["This is\r\na test!", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "This", "is\r\na", "test!" }],
623+
["This is\r\na test!", new UCodepoint[] { ' ', '\r', '\n' }, int.MaxValue, new[] { "This", "is", "a", "test!" }],
624+
["العربية", new UCodepoint[] { ' ' }, int.MaxValue, new[] { "العربية" }],
625+
["😁🤔😮", new[] { UCodepoint.ReadFromStr("🤔", 0) }, int.MaxValue, new[] { "😁", "😮" }],
626+
];
627+
628+
[TestMethod]
629+
[DynamicData(nameof(SplitIgnoreEmptyTestData))]
630+
public void Split_IgnoreEmpty(string testString, UCodepoint[]? separators, int maxCount, string[] expectedResults)
631+
{
632+
UString us = new(testString);
633+
UString[] expectedUss = expectedResults.Select(er => new UString(er)).ToArray();
634+
635+
Assert.That.SequenceEqual(expectedUss, us.Split(separators, maxCount, StringSplitOptions.RemoveEmptyEntries));
636+
637+
// Test making sure that a substring results in the correct result
638+
us = CreateTestSubstring(testString);
639+
Assert.That.SequenceEqual(expectedUss, us.Split(separators, maxCount, StringSplitOptions.RemoveEmptyEntries));
640+
}
641+
#endregion
545642

546643
#region Private helper methods
547644
private static UString CreateTestSubstring(string? str)

UnicodeHelper.sln.DotSettings

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
<s:Boolean x:Key="/Default/UserDictionary/Words/=Casefolded/@EntryIndexedValue">True</s:Boolean>
1111
<s:Boolean x:Key="/Default/UserDictionary/Words/=Casemapped/@EntryIndexedValue">True</s:Boolean>
1212
<s:Boolean x:Key="/Default/UserDictionary/Words/=Titlecase/@EntryIndexedValue">True</s:Boolean>
13-
<s:Boolean x:Key="/Default/UserDictionary/Words/=Titlecased/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
13+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Titlecased/@EntryIndexedValue">True</s:Boolean>
14+
<s:Boolean x:Key="/Default/UserDictionary/Words/=ustr/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

UnicodeHelper/UCodepoint.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,101 @@ public override string ToString()
389389
{
390390
return uc._value != v;
391391
}
392+
/// <summary>
393+
/// Determines if the a <see cref="UCodepoint"/> is less than an unsigned short integer value
394+
/// </summary>
395+
public static bool operator <(UCodepoint uc, ushort v)
396+
{
397+
return uc._value < v;
398+
}
399+
400+
/// <summary>
401+
/// Determines if the a <see cref="UCodepoint"/> is less than or equal to an unsigned short integer value
402+
/// </summary>
403+
public static bool operator <=(UCodepoint uc, ushort v)
404+
{
405+
return uc._value <= v;
406+
}
407+
408+
/// <summary>
409+
/// Determines if the a <see cref="UCodepoint"/> is greater than an unsigned short integer value
410+
/// </summary>
411+
public static bool operator >(UCodepoint uc, ushort v)
412+
{
413+
return uc._value > v;
414+
}
415+
416+
/// <summary>
417+
/// Determines if the a <see cref="UCodepoint"/> is greater than or equal to an unsigned short integer value
418+
/// </summary>
419+
public static bool operator >=(UCodepoint uc, ushort v)
420+
{
421+
return uc._value >= v;
422+
}
423+
424+
/// <summary>
425+
/// Determines if the a <see cref="UCodepoint"/> is equal to an unsigned short integer value
426+
/// </summary>
427+
public static bool operator ==(UCodepoint uc, ushort v)
428+
{
429+
return uc._value == v;
430+
}
431+
432+
/// <summary>
433+
/// Determines if the a <see cref="UCodepoint"/> is less than a short integer value
434+
/// </summary>
435+
public static bool operator <(UCodepoint uc, short v)
436+
{
437+
return uc._value < v;
438+
}
439+
440+
/// <summary>
441+
/// Determines if the a <see cref="UCodepoint"/> is less than or equal to a short integer value
442+
/// </summary>
443+
public static bool operator <=(UCodepoint uc, short v)
444+
{
445+
return uc._value <= v;
446+
}
447+
448+
/// <summary>
449+
/// Determines if the a <see cref="UCodepoint"/> is greater than a short integer value
450+
/// </summary>
451+
public static bool operator >(UCodepoint uc, short v)
452+
{
453+
return uc._value > v;
454+
}
455+
456+
/// <summary>
457+
/// Determines if the a <see cref="UCodepoint"/> is greater than or equal to a short integer value
458+
/// </summary>
459+
public static bool operator >=(UCodepoint uc, short v)
460+
{
461+
return uc._value >= v;
462+
}
463+
464+
/// <summary>
465+
/// Determines if the a <see cref="UCodepoint"/> is equal to a short integer value
466+
/// </summary>
467+
public static bool operator ==(UCodepoint uc, short v)
468+
{
469+
return uc._value == v;
470+
}
471+
472+
/// <summary>
473+
/// Determines if the a <see cref="UCodepoint"/> is not equal to a short integer value
474+
/// </summary>
475+
public static bool operator !=(UCodepoint uc, short v)
476+
{
477+
return uc._value != v;
478+
}
479+
480+
/// <summary>
481+
/// Determines if the a <see cref="UCodepoint"/> is not equal to an unsigned short value
482+
/// </summary>
483+
public static bool operator !=(UCodepoint uc, ushort v)
484+
{
485+
return uc._value != v;
486+
}
392487

393488
/// <summary>
394489
/// Determines if the a <see cref="UCodepoint"/> is less than a .Net character value

UnicodeHelper/UCodepointExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,13 @@ public static string ToHexString(this UCodepoint uc, HexPadding padding = HexPad
5454

5555
return ((int)uc).ToString(formatString);
5656
}
57+
58+
/// <summary>
59+
/// Converts this codepoint to a <see cref="UString"/>
60+
/// </summary>
61+
public static UString ToUString(this UCodepoint uc)
62+
{
63+
return new UString(uc);
64+
}
5765
}
5866
}

0 commit comments

Comments
 (0)