From a997a885053557ff7df4c5cc7721368460ed5761 Mon Sep 17 00:00:00 2001 From: GoldenCrystal Date: Tue, 9 Aug 2016 00:06:04 +0200 Subject: [PATCH] Split tests in more classes. --- .../CodePointEnumerableTests.cs | 80 ++++++ .../PermissiveCodePointEnumerableTests.cs | 69 +++++ UnicodeInformation.Tests/UnicodeInfoTests.cs | 265 +----------------- .../UnicodeInformation.Tests.csproj | 4 + .../UnicodeRationalNumerTests.cs | 147 ++++++++++ .../XUnitSerializableString.cs | 62 ++++ 6 files changed, 373 insertions(+), 254 deletions(-) create mode 100644 UnicodeInformation.Tests/CodePointEnumerableTests.cs create mode 100644 UnicodeInformation.Tests/PermissiveCodePointEnumerableTests.cs create mode 100644 UnicodeInformation.Tests/UnicodeRationalNumerTests.cs create mode 100644 UnicodeInformation.Tests/XUnitSerializableString.cs diff --git a/UnicodeInformation.Tests/CodePointEnumerableTests.cs b/UnicodeInformation.Tests/CodePointEnumerableTests.cs new file mode 100644 index 0000000..25658a8 --- /dev/null +++ b/UnicodeInformation.Tests/CodePointEnumerableTests.cs @@ -0,0 +1,80 @@ +using System; +using System.Unicode; +using System.Collections.Generic; +using Xunit; +using System.Collections; +using System.Linq; + +namespace UnicodeInformation.Tests +{ + public class CodePointEnumerableTests + { + public static readonly TheoryData EnumerationTestData = new TheoryData + { + { new int[0], "" }, + { new int[] { 0x0041,0x1F600, 0x00E9 }, "\u0041\U0001F600\u00E9" }, + }; + + [Theory] + [MemberData(nameof(EnumerationTestData))] + public void EnumerationShouldHaveExpectedResults(int[] expectedCharacters, string text) + { + var enumerable = text.AsCodePointEnumerable(); + + // Test C# foreach enumeration + { + int i = 0; + foreach (int codePoint in enumerable) + { + Assert.Equal(expectedCharacters[i++], codePoint); + } + Assert.Equal(expectedCharacters.Length, i); + } + + // Test generic enumerable + Assert.Equal(expectedCharacters, from codePoint in enumerable select codePoint); + + // Test legacy enumeration + { + // We could use Enumerable.Cast<>, but we can't guarantee that the LINQ implementation we use wouldn't be smart and cast IEnumerable back to IEnumerable + var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator(); + + int index = 0; + + while (legacyEnumerator.MoveNext()) + { + Assert.True(index < expectedCharacters.Length); + Assert.Equal(expectedCharacters[index++], Assert.IsType(legacyEnumerator.Current)); + } + + Assert.Equal(expectedCharacters.Length, index); + } + } + + [Fact] + public void NullArgumentShouldThrowArgumentNullException() + { + Assert.Throws(() => { foreach (int codePoint in (null as string).AsCodePointEnumerable()) { } }); + } + + public static readonly TheoryData EnumerationFailureTestData = new TheoryData + { + "\uDA00", + "\uDCD0", + "\uDCD0\uDA00", + "\u0041\uDA00", + "\u0041\uDCD0", + "\uDA00\u0041", + "\uDCD0\u0041", + "\uDA00\u0041\uDCD0\u0041", + "\u0041\uDA00\u0041\uDCD0\u0041", + }; + + [Theory] + [MemberData(nameof(EnumerationFailureTestData))] + public void EnumerationOfInvalidUtf16StringsShouldThrowArgumentException(XUnitSerializableString text) + { + Assert.Throws(() => { foreach (int codePoint in ((string)text).AsCodePointEnumerable()) { } }); + } + } +} diff --git a/UnicodeInformation.Tests/PermissiveCodePointEnumerableTests.cs b/UnicodeInformation.Tests/PermissiveCodePointEnumerableTests.cs new file mode 100644 index 0000000..f8528a0 --- /dev/null +++ b/UnicodeInformation.Tests/PermissiveCodePointEnumerableTests.cs @@ -0,0 +1,69 @@ +using System; +using System.Unicode; +using System.Collections.Generic; +using Xunit; +using System.Collections; +using System.Linq; + +namespace UnicodeInformation.Tests +{ + public class PermissiveCodePointEnumerableTests + { + public static readonly TheoryData EnumerationTestData = new TheoryData + { + { new int[0], "" }, + { new int[] { 0xDA00 }, "\uDA00" }, + { new int[] { 0xDCD0 }, "\uDCD0" }, + { new int[] { 0xDCD0, 0xDA00 }, "\uDCD0\uDA00" }, + { new int[] { 0x0041, 0xDA00 }, "\u0041\uDA00" }, + { new int[] { 0x0041, 0xDCD0 }, "\u0041\uDCD0" }, + { new int[] { 0xDA00, 0x0041 }, "\uDA00\u0041" }, + { new int[] { 0xDCD0, 0x0041 }, "\uDCD0\u0041" }, + { new int[] { 0xDA00, 0x0041, 0xDCD0, 0x0041 }, "\uDA00\u0041\uDCD0\u0041" }, + { new int[] { 0x0041, 0xDA00, 0x0041, 0xDCD0, 0x0041 }, "\u0041\uDA00\u0041\uDCD0\u0041" }, + { new int[] { 0x0041, 0x1F600, 0x00E9 }, "\u0041\U0001F600\u00E9" }, + }; + + [Theory] + [MemberData(nameof(EnumerationTestData))] + public void EnumerationShouldHaveExpectedResults(int[] expectedCharacters, XUnitSerializableString text) + { + var enumerable = ((string)text).AsPermissiveCodePointEnumerable(); + + // Test C# foreach enumeration + { + int i = 0; + foreach (int codePoint in enumerable) + { + Assert.Equal(expectedCharacters[i++], codePoint); + } + Assert.Equal(expectedCharacters.Length, i); + } + + // Test generic enumerable + Assert.Equal(expectedCharacters, from codePoint in enumerable select codePoint); + + // Test legacy enumeration + { + // We could use Enumerable.Cast<>, but we can't guarantee that the LINQ implementation we use wouldn't be smart and cast IEnumerable back to IEnumerable + var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator(); + + int index = 0; + + while (legacyEnumerator.MoveNext()) + { + Assert.True(index < expectedCharacters.Length); + Assert.Equal(expectedCharacters[index++], Assert.IsType(legacyEnumerator.Current)); + } + + Assert.Equal(expectedCharacters.Length, index); + } + } + + [Fact] + public void NullArgumentShouldThrowArgumentNullException() + { + Assert.Throws(() => { foreach (int c in (null as string).AsPermissiveCodePointEnumerable()) { } }); + } + } +} diff --git a/UnicodeInformation.Tests/UnicodeInfoTests.cs b/UnicodeInformation.Tests/UnicodeInfoTests.cs index e17df84..58dab54 100644 --- a/UnicodeInformation.Tests/UnicodeInfoTests.cs +++ b/UnicodeInformation.Tests/UnicodeInfoTests.cs @@ -5,211 +5,19 @@ using System.Collections.Generic; using System.Collections; using Xunit; using System.Linq; -using Xunit.Abstractions; -using System.Text; namespace UnicodeInformation.Tests { public class UnicodeInfoTests { - // This class is needed because apparently, somewhere in the process of unit testing, strings with invalid UTF-16 sequences are "fixed", which totally messes up the tests here. - // This is just a wrapper over regular strings… Data is serialized as an array of chars instead of a string. This seems to do the trick. - public class XUnitSerializableString : IEquatable, IXunitSerializable - { - private string value; - - public XUnitSerializableString() : this(null) { } - - public XUnitSerializableString(string value) - { - this.value = value; - } - - void IXunitSerializable.Deserialize(IXunitSerializationInfo info) - { - var chars = info.GetValue("Chars"); - - value = chars != null ? - new string(chars) : - null; - } - - void IXunitSerializable.Serialize(IXunitSerializationInfo info) - { - info.AddValue("Chars", value?.ToCharArray(), typeof(char[])); - } - - public override string ToString() - { - if (string.IsNullOrEmpty(value)) return value; - - var sb = new StringBuilder(value.Length * 6); - - foreach (char c in value) - { - sb.Append(@"\u") - .Append(((ushort)c).ToString("X4")); - } - - return sb.ToString(); - } - - public bool Equals(XUnitSerializableString other) => value == other.value; - public override bool Equals(object obj) => obj is XUnitSerializableString && Equals((XUnitSerializableString)obj); - public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(value); - - public static implicit operator string(XUnitSerializableString text) => text.value; - public static implicit operator XUnitSerializableString(string text) => new XUnitSerializableString(text); - } - [Fact] - public void TestUnicodeVersion() + public void UnicodeVersionShouldBeTheLatestSupported() { Assert.Equal(new Version(9, 0, 0), UnicodeInfo.UnicodeVersion); } - - [Fact] - public void TestCodePointEnumerator() - { - string text = "\u0041\U0001F600\u00E9"; - - var enumerable = text.AsCodePointEnumerable(); - - Assert.Equal(text, enumerable.Text); - - var enumerator = enumerable.GetEnumerator(); - - Assert.True(enumerator.MoveNext()); - Assert.Equal(0x0041, enumerator.Current); - Assert.True(enumerator.MoveNext()); - Assert.Equal(0x1F600, enumerator.Current); - Assert.True(enumerator.MoveNext()); - Assert.Equal(0x00E9, enumerator.Current); - Assert.False(enumerator.MoveNext()); - - var genericEnumerator = ((IEnumerable)enumerable).GetEnumerator(); - - Assert.True(genericEnumerator.MoveNext()); - Assert.Equal(0x0041, genericEnumerator.Current); - Assert.True(genericEnumerator.MoveNext()); - Assert.Equal(0x1F600, genericEnumerator.Current); - Assert.True(genericEnumerator.MoveNext()); - Assert.Equal(0x00E9, genericEnumerator.Current); - Assert.False(genericEnumerator.MoveNext()); - - var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator(); - - Assert.True(legacyEnumerator.MoveNext()); - Assert.Equal(0x0041, legacyEnumerator.Current); - Assert.True(legacyEnumerator.MoveNext()); - Assert.Equal(0x1F600, legacyEnumerator.Current); - Assert.True(legacyEnumerator.MoveNext()); - Assert.Equal(0x00E9, legacyEnumerator.Current); - Assert.False(legacyEnumerator.MoveNext()); - } - - private static void EnumerationFailTest(string text) { foreach (int codePoint in text.AsCodePointEnumerable()) { } } - - public void TestCodePointEnumeratorNullArgument() - { - Assert.Throws - ( - () => - { - foreach (int codePoint in (null as string).AsCodePointEnumerable()) - { - } - } - ); - } - - public static readonly TheoryData InvalidUtf16Strings = new TheoryData - { - "\uDA00", - "\uDCD0", - "\uDCD0\uDA00", - "\u0041\uDA00", - "\u0041\uDCD0", - "\uDA00\u0041", - "\uDCD0\u0041", - "\uDA00\u0041\uDCD0\u0041", - "\u0041\uDA00\u0041\uDCD0\u0041", - }; - - [Theory] - [MemberData(nameof(InvalidUtf16Strings))] - public void TestCodePointEnumeratorFailures(XUnitSerializableString text) - { - Assert.Throws - ( - () => - { - foreach (int codePoint in ((string)text).AsCodePointEnumerable()) - { - } - } - ); - } - public static readonly TheoryData PermissiveCodePointEnumeratorTestData = new TheoryData - { - { new int[0], "" }, - { new int[] { 0xDA00 }, "\uDA00" }, - { new int[] { 0xDCD0 }, "\uDCD0" }, - { new int[] { 0xDCD0, 0xDA00 }, "\uDCD0\uDA00" }, - { new int[] { 0x0041, 0xDA00 }, "\u0041\uDA00" }, - { new int[] { 0x0041, 0xDCD0 }, "\u0041\uDCD0" }, - { new int[] { 0xDA00, 0x0041 }, "\uDA00\u0041" }, - { new int[] { 0xDCD0, 0x0041 }, "\uDCD0\u0041" }, - { new int[] { 0xDA00, 0x0041, 0xDCD0, 0x0041 }, "\uDA00\u0041\uDCD0\u0041" }, - { new int[] { 0x0041, 0xDA00, 0x0041, 0xDCD0, 0x0041 }, "\u0041\uDA00\u0041\uDCD0\u0041" }, - { new int[] { 0x0041, 0x1F600, 0x00E9 }, "\u0041\U0001F600\u00E9" }, - }; - - [Theory] - [MemberData(nameof(PermissiveCodePointEnumeratorTestData))] - public void TestPermissiveCodePointEnumerator(int[] expectedCharacters, XUnitSerializableString text) - { - var enumerable = ((string)text).AsPermissiveCodePointEnumerable(); - - // Test C# foreach enumeration - { - int i = 0; - foreach (int codePoint in enumerable) - { - Assert.Equal(expectedCharacters[i++], codePoint); - } - Assert.Equal(expectedCharacters.Length, i); - } - - // Test generic enumerable - Assert.Equal(expectedCharacters, from codePoint in enumerable select codePoint); - - // Test legacy enumeration - { - // We could use Enumerable.Cast<>, but we can't guarantee that the LINQ implementation we use wouldn't be smart and cast IEnumerable back to IEnumerable - var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator(); - - int index = 0; - - while (legacyEnumerator.MoveNext()) - { - Assert.True(index < expectedCharacters.Length); - Assert.Equal(expectedCharacters[index++], Assert.IsType(legacyEnumerator.Current)); - } - - Assert.Equal(expectedCharacters.Length, index); - } - } - [Fact] - public void TestPermissiveCodePointEnumeratorFailure() - { - Assert.Throws(() => { foreach (int c in (null as string).AsPermissiveCodePointEnumerable()) { } }); - } - - [Fact] - public void TestDisplayTextForControlCharacters() + public void ControlCharactersShouldHaveSpecificDisplayText() { for (int i = 0; i <= 0x20; ++i) { @@ -222,7 +30,7 @@ namespace UnicodeInformation.Tests [InlineData("\u0041", 0x0041)] [InlineData("\U0001F600", 0x1F600)] [InlineData("\u00E9", 0x00E9)] - public void TestDisplayText(string expectedText, int codePoint) + public void DisplayTextShouldReturnExpectedResult(string expectedText, int codePoint) { Assert.Equal(expectedText, UnicodeInfo.GetDisplayText(codePoint)); } @@ -246,7 +54,7 @@ namespace UnicodeInformation.Tests [InlineData(0x0D5D, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "3/20", "MALAYALAM FRACTION THREE TWENTIETHS", "Malayalam")] [InlineData(0x0D59, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "1/40", "MALAYALAM FRACTION ONE FORTIETH", "Malayalam")] [InlineData(0x1F953, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "BACON", "Supplemental Symbols and Pictographs")] - public void TestCharacterInfo(int codePoint, UnicodeCategory expectedCategory, UnicodeNumericType expectedNumericType, string expectedNumericValue, string expectedName, string expectedBlock) + public void CharacterInfoShouldHaveExpectedResults(int codePoint, UnicodeCategory expectedCategory, UnicodeNumericType expectedNumericType, string expectedNumericValue, string expectedName, string expectedBlock) { var info = UnicodeInfo.GetCharInfo(codePoint); Assert.Equal(codePoint, info.CodePoint); @@ -259,63 +67,12 @@ namespace UnicodeInformation.Tests Assert.Equal(expectedBlock, info.Block); } - [Fact] - public void TestRationalNumber() - { - Assert.True(default(UnicodeRationalNumber).IsDefaultValue); - Assert.Equal("1", new UnicodeRationalNumber(1).ToString()); - Assert.Equal("1", new UnicodeRationalNumber(1, 1).ToString()); - Assert.Equal(new UnicodeRationalNumber(1), new UnicodeRationalNumber(1, 1)); - Assert.Equal("1/100", new UnicodeRationalNumber(1, 100).ToString()); - Assert.Equal("-20/7", new UnicodeRationalNumber(-20, 7).ToString()); - Assert.Equal("-5", new UnicodeRationalNumber(-5).ToString()); - Assert.Equal(long.MaxValue.ToString(), new UnicodeRationalNumber(long.MaxValue).ToString()); - Assert.Equal(long.MaxValue.ToString() + "/" + byte.MaxValue.ToString(), new UnicodeRationalNumber(long.MaxValue, byte.MaxValue).ToString()); - Assert.Equal(string.Empty, default(UnicodeRationalNumber).ToString()); - - Assert.Equal(new UnicodeRationalNumber(0), UnicodeRationalNumber.Parse("0")); - Assert.Equal(new UnicodeRationalNumber(1), UnicodeRationalNumber.Parse("1")); - Assert.Equal(new UnicodeRationalNumber(1), UnicodeRationalNumber.Parse("1/1")); - Assert.Equal(new UnicodeRationalNumber(1, 10), UnicodeRationalNumber.Parse("1/10")); - Assert.NotEqual(new UnicodeRationalNumber(2, 10), UnicodeRationalNumber.Parse("1/10")); - Assert.NotEqual(new UnicodeRationalNumber(1, 20), UnicodeRationalNumber.Parse("1/10")); - Assert.NotEqual(new UnicodeRationalNumber(2, 2), new UnicodeRationalNumber(1, 1)); - - Assert.Throws(() => UnicodeRationalNumber.Parse(null)); - Assert.Throws(() => UnicodeRationalNumber.Parse(string.Empty)); - - var numbers = new[] - { - default(UnicodeRationalNumber), - new UnicodeRationalNumber(0), - new UnicodeRationalNumber(1), - new UnicodeRationalNumber(1, 10), - new UnicodeRationalNumber(1, 100), - new UnicodeRationalNumber(10), - new UnicodeRationalNumber(100), - new UnicodeRationalNumber(1000), - new UnicodeRationalNumber(1000000), - new UnicodeRationalNumber(1000000000), - new UnicodeRationalNumber(1000000000000), - }; - - var hashSet = new HashSet(); - - // Verify that all numbers are unique - foreach (var number in numbers) - Assert.True(hashSet.Add(number)); - - // Verify that all numbers are already in the list - foreach (var number in numbers) - Assert.False(hashSet.Add(number)); - } - #if DEBUG [Theory] [InlineData('\0')] [InlineData('\uABFF')] [InlineData('\uD7A5')] - public void TestHangulNameFailure(char codePoint) + public void HangulNameShouldFailForNonHangulCodePoints(char codePoint) { Assert.Throws(() => HangulInfo.GetHangulName(codePoint)); } @@ -326,7 +83,7 @@ namespace UnicodeInformation.Tests [InlineData("HANGUL SYLLABLE PWAENG", 0xD439)] [InlineData("HANGUL SYLLABLE PANJ", 0xD311)] [InlineData("HANGUL SYLLABLE TOLM", 0xD1AA)] - public void TestHangulName(string expectedName, int codePoint) + public void HangulNameShouldReturnExpectedResult(string expectedName, int codePoint) { Assert.Equal(expectedName, UnicodeInfo.GetName(codePoint)); } @@ -336,7 +93,7 @@ namespace UnicodeInformation.Tests [InlineData("Miscellaneous Technical", 0x2307)] [InlineData("Hangul Syllables", 0xD311)] [InlineData("Miscellaneous Symbols and Pictographs", 0x1F574)] - public void TestBlockName(string expectedBlockName, int codePoint) + public void MethodGetBlockNameShouldHaveExpectedResult(string expectedBlockName, int codePoint) { Assert.Equal(expectedBlockName, UnicodeInfo.GetBlockName(codePoint)); } @@ -453,7 +210,7 @@ namespace UnicodeInformation.Tests } [Fact] - public void TestGetNameSuccess() + public void MethodGetNameShouldNeverFail() { for (int i = 0; i <= 0x10FFFF; i++) { @@ -462,7 +219,7 @@ namespace UnicodeInformation.Tests } [Fact] - public void TestGetDisplayTextSuccess() + public void MethodGetDisplayTextShouldNeverFail() { for (int i = 0; i <= 0x10FFFF; i++) { @@ -471,7 +228,7 @@ namespace UnicodeInformation.Tests } [Fact] - public void TestGetCategorySuccess() + public void MethodGetCategoryShouldNeverFail() { for (int i = 0; i <= 0x10FFFF; i++) { @@ -480,7 +237,7 @@ namespace UnicodeInformation.Tests } [Fact] - public void TestGetCharInfoSuccess() + public void MethodGetCharInfoShouldNeverFail() { for (int i = 0; i <= 0x10FFFF; i++) { diff --git a/UnicodeInformation.Tests/UnicodeInformation.Tests.csproj b/UnicodeInformation.Tests/UnicodeInformation.Tests.csproj index 21494bd..1291411 100644 --- a/UnicodeInformation.Tests/UnicodeInformation.Tests.csproj +++ b/UnicodeInformation.Tests/UnicodeInformation.Tests.csproj @@ -70,8 +70,12 @@ Properties\AssemblyInfo.Common.cs + + + + diff --git a/UnicodeInformation.Tests/UnicodeRationalNumerTests.cs b/UnicodeInformation.Tests/UnicodeRationalNumerTests.cs new file mode 100644 index 0000000..d1bddaa --- /dev/null +++ b/UnicodeInformation.Tests/UnicodeRationalNumerTests.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Unicode; +using Xunit; + +namespace UnicodeInformation.Tests +{ + public class UnicodeRationalNumerTests + { + [Fact] + public void DefaultValueShouldBeDetectedAsSuch() + { + Assert.True(default(UnicodeRationalNumber).IsDefaultValue); + Assert.Equal(string.Empty, default(UnicodeRationalNumber).ToString()); + } + + public static readonly TheoryData Numerators = new TheoryData + { + 0, + 1, + long.MaxValue, + long.MinValue + }; + + [Theory] + [MemberData(nameof(Numerators))] + public void NumbersAndFractionOverOneShouldBeEqual(long numerator) + { + Assert.Equal(new UnicodeRationalNumber(numerator), new UnicodeRationalNumber(numerator, 1)); + Assert.Equal(new UnicodeRationalNumber(numerator).GetHashCode(), new UnicodeRationalNumber(numerator, 1).GetHashCode()); + } + + [Theory] + [InlineData("1/10", "10/1")] + [InlineData("2/10", "1/10")] + [InlineData("1/20", "1/10")] + [InlineData("2/2", "1/1")] + [InlineData("2/1", "1/2")] + public void DifferentRationalNumbersShouldNotBeDeterminedEqual(string number1, string number2) + { + Assert.NotEqual(UnicodeRationalNumber.Parse(number1), UnicodeRationalNumber.Parse(number2)); + Assert.NotEqual(UnicodeRationalNumber.Parse(number2), UnicodeRationalNumber.Parse(number1)); + } + + public static readonly TheoryData StringConversionTestData = new TheoryData + { + { "0", 0, 1 }, + { "1", 1, 1 }, + { "1/100", 1, 100 }, + { "-20/7", -20, 7 }, + { "-5", -5, 1 }, + { "-9223372036854775808", long.MinValue, 1 }, + { "9223372036854775807", long.MaxValue, 1 }, + { "9223372036854775807/255", long.MaxValue, byte.MaxValue }, + }; + + [Theory] + [MemberData(nameof(StringConversionTestData))] + public void MethodToStringShouldReturnExpectedResult(string expectedText, long numerator, byte denominator) + { + Assert.Equal(expectedText, new UnicodeRationalNumber(numerator, denominator).ToString()); + } + + [Fact] + public void ParsingNullValueShoudlFail() + { + Assert.Throws(() => UnicodeRationalNumber.Parse(null)); + } + + [Fact] + public void ParsingEmptyValueShoudlFail() + { + Assert.Throws(() => UnicodeRationalNumber.Parse(string.Empty)); + } + + [Theory] + [InlineData(0, "0")] + [InlineData(0, "0/1")] + [InlineData(1, "1")] + [InlineData(1, "1/1")] + [InlineData(long.MaxValue, "9223372036854775807")] + [InlineData(long.MaxValue, "9223372036854775807/1")] + [InlineData(long.MinValue, "-9223372036854775808")] + [InlineData(long.MinValue, "-9223372036854775808/1")] + public void ParsingCanReturnSimpleNumber(long expectedNumber, string text) + { + Assert.Equal(new UnicodeRationalNumber(expectedNumber), UnicodeRationalNumber.Parse(text)); + } + + public static readonly TheoryData FractionParsingTestData = new TheoryData + { + { 0, 1, "0" }, + { 0, 1, "0/1" }, + { 1, 1, "1" }, + { 1, 1, "1/1" }, + { 1, 10, "1/10" }, + { 1, 255, "1/255" }, + { 3, 4, "3/4" }, + { 6, 8, "6/8" }, + { 1, 255, "1/255" }, + { long.MaxValue, 1, "9223372036854775807" }, + { long.MaxValue, 1, "9223372036854775807/1" }, + { long.MinValue, 1, "-9223372036854775808" }, + { long.MinValue, 1, "-9223372036854775808/1" }, + { long.MaxValue, byte.MaxValue, "9223372036854775807/255" }, + }; + + [Theory] + [MemberData(nameof(FractionParsingTestData))] + public void ParsingCanReturnFraction(long expectedNumerator, byte expectedDenominator, string text) + { + Assert.Equal(new UnicodeRationalNumber(expectedNumerator, expectedDenominator), UnicodeRationalNumber.Parse(text)); + } + + [Fact] + public void EqualityComparisonAndHashCodeShouldWorkAsExpected() + { + var numbers = new[] + { + default(UnicodeRationalNumber), + new UnicodeRationalNumber(0), + new UnicodeRationalNumber(1), + new UnicodeRationalNumber(1, 10), + new UnicodeRationalNumber(1, 100), + new UnicodeRationalNumber(10), + new UnicodeRationalNumber(100), + new UnicodeRationalNumber(1000), + new UnicodeRationalNumber(1000000), + new UnicodeRationalNumber(1000000000), + new UnicodeRationalNumber(1000000000000), + }; + + var hashSet = new HashSet(); + + // Verify that all numbers are unique + foreach (var number in numbers) + Assert.True(hashSet.Add(number)); + + // Verify that all numbers are already in the list + foreach (var number in numbers) + Assert.False(hashSet.Add(number)); + } + } +} diff --git a/UnicodeInformation.Tests/XUnitSerializableString.cs b/UnicodeInformation.Tests/XUnitSerializableString.cs new file mode 100644 index 0000000..7548158 --- /dev/null +++ b/UnicodeInformation.Tests/XUnitSerializableString.cs @@ -0,0 +1,62 @@ +using System; +using System.Unicode; +using System.Globalization; +using System.Collections.Generic; +using System.Collections; +using Xunit; +using System.Linq; +using Xunit.Abstractions; +using System.Text; + +namespace UnicodeInformation.Tests +{ + // This class is needed because apparently, somewhere in the process of unit testing, strings with invalid UTF-16 sequences are "fixed", which totally messes up the tests here. + // This is just a wrapper over regular strings… Data is serialized as an array of chars instead of a string. This seems to do the trick. + public class XUnitSerializableString : IEquatable, IXunitSerializable + { + private string value; + + public XUnitSerializableString() : this(null) { } + + public XUnitSerializableString(string value) + { + this.value = value; + } + + void IXunitSerializable.Deserialize(IXunitSerializationInfo info) + { + var chars = info.GetValue("Chars"); + + value = chars != null ? + new string(chars) : + null; + } + + void IXunitSerializable.Serialize(IXunitSerializationInfo info) + { + info.AddValue("Chars", value?.ToCharArray(), typeof(char[])); + } + + public override string ToString() + { + if (string.IsNullOrEmpty(value)) return value; + + var sb = new StringBuilder(value.Length * 6); + + foreach (char c in value) + { + sb.Append(@"\u") + .Append(((ushort)c).ToString("X4")); + } + + return sb.ToString(); + } + + public bool Equals(XUnitSerializableString other) => value == other.value; + public override bool Equals(object obj) => obj is XUnitSerializableString && Equals((XUnitSerializableString)obj); + public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(value); + + public static implicit operator string(XUnitSerializableString text) => text.value; + public static implicit operator XUnitSerializableString(string text) => new XUnitSerializableString(text); + } +}