--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace System.Tests
+{
+ public static class Helpers
+ {
+ private static Type s_refEmitType;
+
+ public static IEnumerable<Type> NonRuntimeTypes
+ {
+ get
+ {
+ if (PlatformDetection.IsReflectionEmitSupported)
+ yield return RefEmitType();
+
+ yield return new NonRuntimeType();
+ }
+ }
+
+ private static Type RefEmitType()
+ {
+ if (s_refEmitType == null)
+ {
+ AssemblyName assemblyName = new AssemblyName("AssemblyName");
+ AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder mboduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
+
+ TypeBuilder typeBuilder = mboduleBuilder.DefineType("TestType", TypeAttributes.Public);
+
+ GenericTypeParameterBuilder[] typeParams = typeBuilder.DefineGenericParameters("T");
+ s_refEmitType = typeParams[0].UnderlyingSystemType;
+ }
+
+ return s_refEmitType;
+ }
+
+ private sealed class NonRuntimeType : MockType
+ {
+ public sealed override Type UnderlyingSystemType => this;
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Reflection;
-using System.Reflection.Emit;
-
-namespace System.Tests
-{
- public static partial class Helpers
- {
- private static Type s_refEmitType;
-
- public static IEnumerable<Type> NonRuntimeTypes
- {
- get
- {
- if (PlatformDetection.IsReflectionEmitSupported)
- yield return RefEmitType();
-
- yield return new NonRuntimeType();
- }
- }
-
- private static Type RefEmitType()
- {
- if (s_refEmitType == null)
- {
- AssemblyName assemblyName = new AssemblyName("AssemblyName");
- AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
- ModuleBuilder mboduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
-
- TypeBuilder typeBuilder = mboduleBuilder.DefineType("TestType", TypeAttributes.Public);
-
- GenericTypeParameterBuilder[] typeParams = typeBuilder.DefineGenericParameters("T");
- s_refEmitType = typeParams[0].UnderlyingSystemType;
- }
-
- return s_refEmitType;
- }
-
- private sealed class NonRuntimeType : MockType
- {
- public sealed override Type UnderlyingSystemType => this;
- }
- }
-}
<Compile Include="$(CommonTestPath)\System\Collections\IEnumerable.NonGeneric.Tests.cs">
<Link>Common\System\Collections\IEnumerable.NonGeneric.Tests.cs</Link>
</Compile>
+ <Compile Include="Helpers.cs" />
<Compile Include="Microsoft\Win32\SafeHandles\CriticalHandleZeroOrMinusOneIsInvalid.cs" />
<Compile Include="Microsoft\Win32\SafeHandles\SafeHandleZeroOrMinusOneIsInvalid.cs" />
<Compile Include="System\AccessViolationExceptionTests.cs" />
<Compile Include="System\ActivatorTests.cs" />
<Compile Include="System\ActivatorTests.Generic.cs" />
+ <Compile Include="System\AmbiguousImplementationExceptionTests.cs" />
<Compile Include="System\ArgumentExceptionTests.cs" />
<Compile Include="System\ArgumentNullExceptionTests.cs" />
<Compile Include="System\ArgumentOutOfRangeExceptionTests.cs" />
<Compile Include="System\GCTests.cs" />
<Compile Include="System\GuidTests.cs" />
<Compile Include="System\HandleTests.cs" />
+ <Compile Include="System\HashCodeTests.cs" />
<Compile Include="System\IndexOutOfRangeExceptionTests.cs" />
+ <Compile Include="System\IndexTests.cs" />
<Compile Include="System\Int16Tests.cs" />
<Compile Include="System\Int32Tests.cs" />
<Compile Include="System\Int64Tests.cs" />
<Compile Include="System\ParamArrayAttributeTests.cs" />
<Compile Include="System\PlatformNotSupportedExceptionTests.cs" />
<Compile Include="System\PseudoCustomAttributeTests.cs" />
+ <Compile Include="System\RangeTests.cs" />
<Compile Include="System\RankExceptionTests.cs" />
<Compile Include="System\SByteTests.cs" />
<Compile Include="System\SingleTests.cs" />
<Compile Include="System\StackOverflowExceptionTests.cs" />
<Compile Include="System\StringComparerTests.cs" />
<Compile Include="System\StringGetHashCodeTests.cs" />
+ <Compile Include="System\StringTests.cs" />
<Compile Include="System\String.SplitTests.cs" />
<Compile Include="System\SystemExceptionTests.cs" />
<Compile Include="System\TimeoutExceptionTests.cs" />
<Compile Include="System\TimeZoneInfoTests.cs" />
<Compile Include="System\TimeZoneTests.cs" />
<Compile Include="System\TimeZoneNotFoundExceptionTests.cs" />
+ <Compile Include="System\TypedReferenceTests.cs" />
<Compile Include="System\TypeLoadExceptionTests.cs" />
<Compile Include="System\TypeUnloadedExceptionTests.cs" />
<Compile Include="System\TupleTests.cs" />
<Compile Include="System\Reflection\AssemblyTitleAttributeTests.cs" />
<Compile Include="System\Reflection\AssemblyTrademarkAttributeTests.cs" />
<Compile Include="System\Reflection\AssemblyVersionAttributeTests.cs" />
+ <Compile Include="System\Reflection\BindingFlagsDoNotWrap.cs" />
<Compile Include="System\Reflection\CustomAttributeDataTests.cs" />
<Compile Include="System\Reflection\CustomAttributesTestData.cs" />
<Compile Include="System\Reflection\CustomAttribute_Named_Typed_ArgumentTests.cs" />
<Compile Include="System\Reflection\DefaultMemberAttributeTests.cs" />
+ <Compile Include="System\Reflection\InvokeRefReturn.cs" />
+ <Compile Include="System\Reflection\IsCollectibleTests.cs" />
<Compile Include="System\Reflection\MethodBaseTests.cs" />
<Compile Include="System\Reflection\MethodBodyTests.cs" />
<Compile Include="System\Reflection\ModuleTests.cs" />
<Compile Include="System\ExitCodeTests.Unix.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="System\HashCodeTests.netcoreapp.cs" />
- <Compile Include="Helpers.netcoreapp.cs" />
- <Compile Include="System\ActivatorTests.netcoreapp.cs" />
- <Compile Include="System\AmbiguousImplementationExceptionTests.cs" />
- <Compile Include="System\ArrayTests.netcoreapp.cs" />
- <Compile Include="System\ArraySegmentTests.netcoreapp.cs" />
- <Compile Include="System\BooleanTests.netcoreapp.cs" />
- <Compile Include="System\ByteTests.netcoreapp.cs" />
- <Compile Include="System\CharTests.netcoreapp.cs" />
- <Compile Include="System\DateTimeTests.netcoreapp.cs" />
- <Compile Include="System\DateTimeOffsetTests.netcoreapp.cs" />
- <Compile Include="System\DecimalTests.netcoreapp.cs" />
- <Compile Include="System\EnumTests.netcoreapp.cs" />
- <Compile Include="System\FormattableStringTests.netcoreapp.cs" />
- <Compile Include="System\GCTests.netcoreapp.cs" />
- <Compile Include="System\GuidTests.netcoreapp.cs" />
- <Compile Include="System\IndexTests.cs" />
- <Compile Include="System\Int16Tests.netcoreapp.cs" />
- <Compile Include="System\Int32Tests.netcoreapp.cs" />
- <Compile Include="System\Int64Tests.netcoreapp.cs" />
- <Compile Include="System\IntPtrTests.netcoreapp.cs" />
- <Compile Include="System\Collections\Generic\KeyValuePairTests.netcoreapp.cs" />
- <Compile Include="System\LazyTests.netcoreapp.cs" />
- <Compile Include="System\RangeTests.cs" />
- <Compile Include="System\SByteTests.netcoreapp.cs" />
- <Compile Include="System\StringComparerTests.netcoreapp.cs" />
- <Compile Include="System\StringGetHashCodeTests.netcoreapp.cs" />
- <Compile Include="System\StringTests.netcoreapp.cs" />
- <Compile Include="System\TimeSpanTests.netcoreapp.cs" />
- <Compile Include="System\TypedReferenceTests.cs" />
- <Compile Include="System\UIntPtrTests.netcoreapp.cs" />
- <Compile Include="System\UInt16Tests.netcoreapp.cs" />
- <Compile Include="System\UInt32Tests.netcoreapp.cs" />
- <Compile Include="System\UInt64Tests.netcoreapp.cs" />
- <Compile Include="System\VersionTests.netcoreapp.cs" />
- <Compile Include="System\ComponentModel\DefaultValueAttributeTests.netcoreapp.cs" />
- <Compile Include="System\Reflection\BindingFlagsDoNotWrap.netcoreapp.cs" />
- <Compile Include="System\Reflection\InvokeRefReturn.netcoreapp.cs" />
- <Compile Include="System\Reflection\IsCollectibleTests.cs" />
- <!-- missing method 'AssemblyLoadContext..ctor(bool) -->
- <Compile Include="System\Reflection\MethodBaseTests.netcoreapp.cs" />
- <Compile Include="System\Reflection\SignatureTypes.netcoreapp.cs" />
- <Compile Include="System\Reflection\TypeDelegatorTests.netcoreapp.cs" />
- <Compile Include="System\Runtime\CompilerServices\AttributesTests.netcoreapp.cs" />
+ <Compile Include="System\Reflection\SignatureTypes.cs" />
<Compile Include="System\Runtime\CompilerServices\CallerArgumentExpressionAttributeTests.cs" />
- <Compile Include="System\Runtime\CompilerServices\ConditionalWeakTableTests.netcoreapp.cs" />
- <Compile Include="System\Runtime\CompilerServices\MethodImplAttributeTests.netcoreapp.cs" />
- <Compile Include="System\Runtime\CompilerServices\RuntimeHelpersTests.netcoreapp.cs" />
- <Compile Include="System\Runtime\CompilerServices\RuntimeFeatureTests.netcoreapp.cs" />
+ <Compile Include="System\Runtime\CompilerServices\MethodImplAttributeTests.cs" />
+ <Compile Include="System\Runtime\CompilerServices\RuntimeFeatureTests.cs" />
<Compile Include="System\Runtime\CompilerServices\RuntimeWrappedExceptionTests.cs" />
- <Compile Include="System\Runtime\ExceptionServices\ExceptionDispatchInfoTests.netcoreapp.cs" />
- <Compile Include="System\Text\ASCIIUtilityTests.netcoreapp.cs" />
- <Compile Include="System\Text\RuneTests.netcoreapp.cs" />
- <Compile Include="System\Text\RuneTests.TestData.netcoreapp.cs" />
- <Compile Include="System\Text\StringBuilderTests.netcoreapp.cs" />
- <Compile Include="System\Text\Unicode\UnicodeData.netcoreapp.cs" />
- <Compile Include="System\Text\Unicode\Utf16UtilityTests.ValidateChars.netcoreapp.cs" />
- <Compile Include="System\Text\Unicode\Utf8Tests.netcoreapp.cs" />
- <Compile Include="System\Text\Unicode\Utf8Tests.ToBytes.netcoreapp.cs" />
- <Compile Include="System\Text\Unicode\Utf8Tests.ToChars.netcoreapp.cs" />
- <Compile Include="System\Text\Unicode\Utf8UtilityTests.ValidateBytes.netcoreapp.cs" />
- <Compile Include="System\Type\TypePropertyTests.netcoreapp.cs" />
- <Compile Include="System\Type\TypeTests.netcoreapp.cs" />
- <Compile Include="System\ArgIteratorTests.netcoreapp.cs" />
- <Compile Include="System\DoubleTests.netcoreapp.cs" />
- <Compile Include="System\SingleTests.netcoreapp.cs" />
+ <Compile Include="System\Runtime\ExceptionServices\ExceptionDispatchInfoTests.cs" />
+ <Compile Include="System\Text\ASCIIUtilityTests.cs" />
+ <Compile Include="System\Text\RuneTests.cs" />
+ <Compile Include="System\Text\RuneTests.TestData.cs" />
+ <Compile Include="System\Text\Unicode\UnicodeData.cs" />
+ <Compile Include="System\Text\Unicode\Utf16UtilityTests.ValidateChars.cs" />
+ <Compile Include="System\Text\Unicode\Utf8Tests.cs" />
+ <Compile Include="System\Text\Unicode\Utf8UtilityTests.ValidateBytes.cs" />
+ <Compile Include="System\ArgIteratorTests.cs" />
<Compile Include="$(CommonPath)\..\tests\System\RealFormatterTestsBase.netcoreapp.cs" Link="System\RealFormatterTestsBase.netcoreapp.cs" />
- <Compile Include="System\RealFormatterTests.netcoreapp.cs" />
+ <Compile Include="System\RealFormatterTests.cs" />
<Compile Include="$(CommonPath)\..\tests\System\RealParserTestsBase.netcoreapp.cs" Link="System\RealParserTestsBase.netcoreapp.cs" />
<Compile Include="System\RealParserTests.netcoreapp.cs" />
</ItemGroup>
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
+using System.IO;
using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.Remoting;
+using Microsoft.DotNet.RemoteExecutor;
using Xunit;
namespace System.Tests
Activator.CreateInstance(typeof(ClassWithIsTestedAttribute), null, null);
Activator.CreateInstance(typeof(ClassWithIsTestedAttribute), null, new object[] { });
}
+
+ [Fact]
+ public void CreateInstance_NonPublicValueTypeWithPrivateDefaultConstructor_Success()
+ {
+ AssemblyName assemblyName = new AssemblyName("Assembly");
+ AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+ TypeBuilder typeBuilder = moduleBuilder.DefineType("Type", TypeAttributes.Public, typeof(ValueType));
+
+ FieldBuilder fieldBuilder = typeBuilder.DefineField("_field", typeof(int), FieldAttributes.Public);
+ ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig, CallingConventions.Standard, new Type[0]);
+
+ ILGenerator generator = constructorBuilder.GetILGenerator();
+ generator.Emit(OpCodes.Ldarg_0);
+ generator.Emit(OpCodes.Ldc_I4, -1);
+ generator.Emit(OpCodes.Stfld, fieldBuilder);
+ generator.Emit(OpCodes.Ret);
+
+ Type type = typeBuilder.CreateType();
+ FieldInfo field = type.GetField("_field");
+
+ // Activator holds a cache of constructors and the types to which they belong.
+ // Test caching behaviour by activating multiple times.
+ object v1 = Activator.CreateInstance(type, nonPublic: true);
+ Assert.Equal(-1, field.GetValue(v1));
+
+ object v2 = Activator.CreateInstance(type, nonPublic: true);
+ Assert.Equal(-1, field.GetValue(v2));
+ }
+
+ [Fact]
+ public void CreateInstance_PublicOnlyValueTypeWithPrivateDefaultConstructor_ThrowsMissingMethodException()
+ {
+ AssemblyName assemblyName = new AssemblyName("Assembly");
+ AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+ TypeBuilder typeBuilder = moduleBuilder.DefineType("Type", TypeAttributes.Public, typeof(ValueType));
+
+ FieldBuilder fieldBuilder = typeBuilder.DefineField("_field", typeof(int), FieldAttributes.Public);
+ ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig, CallingConventions.Standard, new Type[0]);
+
+ ILGenerator generator = constructorBuilder.GetILGenerator();
+ generator.Emit(OpCodes.Ldarg_0);
+ generator.Emit(OpCodes.Ldc_I4, -1);
+ generator.Emit(OpCodes.Stfld, fieldBuilder);
+ generator.Emit(OpCodes.Ret);
+
+ Type type = typeBuilder.CreateType();
+
+ Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type));
+ Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type, nonPublic: false));
+
+ // Put the private default constructor into the cache and make sure we still throw if public only.
+ Assert.NotNull(Activator.CreateInstance(type, nonPublic: true));
+
+ Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type));
+ Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type, nonPublic: false));
+ }
+
+ [Theory]
+ [MemberData(nameof(TestingCreateInstanceFromObjectHandleData))]
+ public static void TestingCreateInstanceFromObjectHandle(string physicalFileName, string assemblyFile, string type, string returnedFullNameType, Type exceptionType)
+ {
+ ObjectHandle oh = null;
+
+ if (exceptionType != null)
+ {
+ Assert.Throws(exceptionType, () => Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type));
+ }
+ else
+ {
+ oh = Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type);
+ CheckValidity(oh, returnedFullNameType);
+ }
+
+ if (exceptionType != null)
+ {
+ Assert.Throws(exceptionType, () => Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type, null));
+ }
+ else
+ {
+ oh = Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type, null);
+ CheckValidity(oh, returnedFullNameType);
+ }
+ Assert.True(File.Exists(physicalFileName));
+ }
+
+ public static TheoryData<string, string, string, string, Type> TestingCreateInstanceFromObjectHandleData => new TheoryData<string, string, string, string, Type>()
+ {
+ // string physicalFileName, string assemblyFile, string typeName, returnedFullNameType, expectedException
+ { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassSample", "PublicClassSample", null },
+ { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclasssample", "PublicClassSample", typeof(TypeLoadException) },
+
+ { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PrivateClassSample", "PrivateClassSample", null },
+ { "TestLoadAssembly.dll", "testloadassembly.dll", "privateclasssample", "PrivateClassSample", typeof(TypeLoadException) },
+
+ { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassNoDefaultConstructorSample", "PublicClassNoDefaultConstructorSample", typeof(MissingMethodException) },
+ { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclassnodefaultconstructorsample", "PublicClassNoDefaultConstructorSample", typeof(TypeLoadException) }
+ };
+
+ [Theory]
+ [MemberData(nameof(TestingCreateInstanceObjectHandleData))]
+ public static void TestingCreateInstanceObjectHandle(string assemblyName, string type, string returnedFullNameType, Type exceptionType, bool returnNull)
+ {
+ ObjectHandle oh = null;
+
+ if (exceptionType != null)
+ {
+ Assert.Throws(exceptionType, () => Activator.CreateInstance(assemblyName: assemblyName, typeName: type));
+ }
+ else
+ {
+ oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type);
+ if (returnNull)
+ {
+ Assert.Null(oh);
+ }
+ else
+ {
+ CheckValidity(oh, returnedFullNameType);
+ }
+ }
+
+ if (exceptionType != null)
+ {
+ Assert.Throws(exceptionType, () => Activator.CreateInstance(assemblyName: assemblyName, typeName: type, null));
+ }
+ else
+ {
+ oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type, null);
+ if (returnNull)
+ {
+ Assert.Null(oh);
+ }
+ else
+ {
+ CheckValidity(oh, returnedFullNameType);
+ }
+ }
+ }
+
+ public static TheoryData<string, string, string, Type, bool> TestingCreateInstanceObjectHandleData => new TheoryData<string, string, string, Type, bool>()
+ {
+ // string assemblyName, string typeName, returnedFullNameType, expectedException
+ { "TestLoadAssembly", "PublicClassSample", "PublicClassSample", null, false },
+ { "testloadassembly", "publicclasssample", "PublicClassSample", typeof(TypeLoadException), false },
+
+ { "TestLoadAssembly", "PrivateClassSample", "PrivateClassSample", null, false },
+ { "testloadassembly", "privateclasssample", "PrivateClassSample", typeof(TypeLoadException), false },
+
+ { "TestLoadAssembly", "PublicClassNoDefaultConstructorSample", "PublicClassNoDefaultConstructorSample", typeof(MissingMethodException), false },
+ { "testloadassembly", "publicclassnodefaultconstructorsample", "PublicClassNoDefaultConstructorSample", typeof(TypeLoadException), false },
+
+ { "mscorlib", "System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", "", null, true }
+ };
+
+ [Theory]
+ [MemberData(nameof(TestingCreateInstanceFromObjectHandleFullSignatureData))]
+ public static void TestingCreateInstanceFromObjectHandleFullSignature(string physicalFileName, string assemblyFile, string type, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, string returnedFullNameType)
+ {
+ ObjectHandle oh = Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type, ignoreCase: ignoreCase, bindingAttr: bindingAttr, binder: binder, args: args, culture: culture, activationAttributes: activationAttributes);
+ CheckValidity(oh, returnedFullNameType);
+ Assert.True(File.Exists(physicalFileName));
+ }
+
+ public static IEnumerable<object[]> TestingCreateInstanceFromObjectHandleFullSignatureData()
+ {
+ // string physicalFileName, string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, returnedFullNameType
+ yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" };
+ yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" };
+ yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" };
+ yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" };
+
+ yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample" };
+ yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample" };
+ yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample" };
+ yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample" };
+ }
+
+ [Theory]
+ [MemberData(nameof(TestingCreateInstanceObjectHandleFullSignatureData))]
+ public static void TestingCreateInstanceObjectHandleFullSignature(string assemblyName, string type, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, string returnedFullNameType, bool returnNull)
+ {
+ ObjectHandle oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type, ignoreCase: ignoreCase, bindingAttr: bindingAttr, binder: binder, args: args, culture: culture, activationAttributes: activationAttributes);
+ if (returnNull)
+ {
+ Assert.Null(oh);
+ }
+ else
+ {
+ CheckValidity(oh, returnedFullNameType);
+ }
+ }
+
+ public static IEnumerable<object[]> TestingCreateInstanceObjectHandleFullSignatureData()
+ {
+ // string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, returnedFullNameType
+ yield return new object[] { "TestLoadAssembly", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
+ yield return new object[] { "testloadassembly", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
+ yield return new object[] { "TestLoadAssembly", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
+ yield return new object[] { "testloadassembly", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
+
+ yield return new object[] { "TestLoadAssembly", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
+ yield return new object[] { "testloadassembly", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
+ yield return new object[] { "TestLoadAssembly", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
+ yield return new object[] { "testloadassembly", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
+
+ yield return new object[] { null, typeof(PublicType).FullName, false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, typeof(PublicType).FullName, false };
+ yield return new object[] { null, typeof(PrivateType).FullName, false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, typeof(PrivateType).FullName, false };
+
+ yield return new object[] { "mscorlib", "System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "", true };
+ yield return new object[] { "mscorlib", "SyStEm.NULLABLE`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "", true };
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWinUISupported))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [MemberData(nameof(TestingCreateInstanceObjectHandleFullSignatureWinRTData))]
+ public static void TestingCreateInstanceObjectHandleFullSignatureWinRT(string assemblyName, string type, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, string returnedFullNameType)
+ {
+ ObjectHandle oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type, ignoreCase: ignoreCase, bindingAttr: bindingAttr, binder: binder, args: args, culture: culture, activationAttributes: activationAttributes);
+ CheckValidity(oh, returnedFullNameType);
+ }
+
+ public static IEnumerable<object[]> TestingCreateInstanceObjectHandleFullSignatureWinRTData()
+ {
+ // string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, returnedFullNameType
+ yield return new object[] { "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime", "Windows.Foundation.Collections.StringMap", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "Windows.Foundation.Collections.StringMap" };
+ }
+
+ private static void CheckValidity(ObjectHandle instance, string expected)
+ {
+ Assert.NotNull(instance);
+ Assert.Equal(expected, instance.Unwrap().GetType().FullName);
+ }
+
+ public class PublicType
+ {
+ public PublicType() { }
+ }
+
+ [Fact]
+ public static void CreateInstanceAssemblyResolve()
+ {
+ RemoteExecutor.Invoke(() =>
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) => Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), "TestLoadAssembly.dll"));
+ Assert.Throws<FileLoadException>(() => Activator.CreateInstance(",,,,", "PublicClassSample"));
+ }).Dispose();
+ }
+
+ [Fact]
+ public void CreateInstance_TypeBuilder_ThrowsNotSupportedException()
+ {
+ AssemblyName assemblyName = new AssemblyName("Assembly");
+ AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+ TypeBuilder typeBuilder = moduleBuilder.DefineType("Type", TypeAttributes.Public);
+
+ Assert.Throws<ArgumentException>("type", () => Activator.CreateInstance(typeBuilder));
+ Assert.Throws<NotSupportedException>(() => Activator.CreateInstance(typeBuilder, new object[0]));
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Runtime.Remoting;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class ActivatorTests
- {
- [Fact]
- public void CreateInstance_NonPublicValueTypeWithPrivateDefaultConstructor_Success()
- {
- AssemblyName assemblyName = new AssemblyName("Assembly");
- AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
- ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
- TypeBuilder typeBuilder = moduleBuilder.DefineType("Type", TypeAttributes.Public, typeof(ValueType));
-
- FieldBuilder fieldBuilder = typeBuilder.DefineField("_field", typeof(int), FieldAttributes.Public);
- ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig, CallingConventions.Standard, new Type[0]);
-
- ILGenerator generator = constructorBuilder.GetILGenerator();
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Ldc_I4, -1);
- generator.Emit(OpCodes.Stfld, fieldBuilder);
- generator.Emit(OpCodes.Ret);
-
- Type type = typeBuilder.CreateType();
- FieldInfo field = type.GetField("_field");
-
- // Activator holds a cache of constructors and the types to which they belong.
- // Test caching behaviour by activating multiple times.
- object v1 = Activator.CreateInstance(type, nonPublic: true);
- Assert.Equal(-1, field.GetValue(v1));
-
- object v2 = Activator.CreateInstance(type, nonPublic: true);
- Assert.Equal(-1, field.GetValue(v2));
- }
-
- [Fact]
- public void CreateInstance_PublicOnlyValueTypeWithPrivateDefaultConstructor_ThrowsMissingMethodException()
- {
- AssemblyName assemblyName = new AssemblyName("Assembly");
- AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
- ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
- TypeBuilder typeBuilder = moduleBuilder.DefineType("Type", TypeAttributes.Public, typeof(ValueType));
-
- FieldBuilder fieldBuilder = typeBuilder.DefineField("_field", typeof(int), FieldAttributes.Public);
- ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig, CallingConventions.Standard, new Type[0]);
-
- ILGenerator generator = constructorBuilder.GetILGenerator();
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Ldc_I4, -1);
- generator.Emit(OpCodes.Stfld, fieldBuilder);
- generator.Emit(OpCodes.Ret);
-
- Type type = typeBuilder.CreateType();
-
- Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type));
- Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type, nonPublic: false));
-
- // Put the private default constructor into the cache and make sure we still throw if public only.
- Assert.NotNull(Activator.CreateInstance(type, nonPublic: true));
-
- Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type));
- Assert.Throws<MissingMethodException>(() => Activator.CreateInstance(type, nonPublic: false));
- }
-
- [Theory]
- [MemberData(nameof(TestingCreateInstanceFromObjectHandleData))]
- public static void TestingCreateInstanceFromObjectHandle(string physicalFileName, string assemblyFile, string type, string returnedFullNameType, Type exceptionType)
- {
- ObjectHandle oh = null;
-
- if (exceptionType != null)
- {
- Assert.Throws(exceptionType, () => Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type));
- }
- else
- {
- oh = Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type);
- CheckValidity(oh, returnedFullNameType);
- }
-
- if (exceptionType != null)
- {
- Assert.Throws(exceptionType, () => Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type, null));
- }
- else
- {
- oh = Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type, null);
- CheckValidity(oh, returnedFullNameType);
- }
- Assert.True(File.Exists(physicalFileName));
- }
-
- public static TheoryData<string, string, string, string, Type> TestingCreateInstanceFromObjectHandleData => new TheoryData<string, string, string, string, Type>()
- {
- // string physicalFileName, string assemblyFile, string typeName, returnedFullNameType, expectedException
- { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassSample", "PublicClassSample", null },
- { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclasssample", "PublicClassSample", typeof(TypeLoadException) },
-
- { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PrivateClassSample", "PrivateClassSample", null },
- { "TestLoadAssembly.dll", "testloadassembly.dll", "privateclasssample", "PrivateClassSample", typeof(TypeLoadException) },
-
- { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassNoDefaultConstructorSample", "PublicClassNoDefaultConstructorSample", typeof(MissingMethodException) },
- { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclassnodefaultconstructorsample", "PublicClassNoDefaultConstructorSample", typeof(TypeLoadException) }
- };
-
- [Theory]
- [MemberData(nameof(TestingCreateInstanceObjectHandleData))]
- public static void TestingCreateInstanceObjectHandle(string assemblyName, string type, string returnedFullNameType, Type exceptionType, bool returnNull)
- {
- ObjectHandle oh = null;
-
- if (exceptionType != null)
- {
- Assert.Throws(exceptionType, () => Activator.CreateInstance(assemblyName: assemblyName, typeName: type));
- }
- else
- {
- oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type);
- if (returnNull)
- {
- Assert.Null(oh);
- }
- else
- {
- CheckValidity(oh, returnedFullNameType);
- }
- }
-
- if (exceptionType != null)
- {
- Assert.Throws(exceptionType, () => Activator.CreateInstance(assemblyName: assemblyName, typeName: type, null));
- }
- else
- {
- oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type, null);
- if (returnNull)
- {
- Assert.Null(oh);
- }
- else
- {
- CheckValidity(oh, returnedFullNameType);
- }
- }
- }
-
- public static TheoryData<string, string, string, Type, bool> TestingCreateInstanceObjectHandleData => new TheoryData<string, string, string, Type, bool>()
- {
- // string assemblyName, string typeName, returnedFullNameType, expectedException
- { "TestLoadAssembly", "PublicClassSample", "PublicClassSample", null, false },
- { "testloadassembly", "publicclasssample", "PublicClassSample", typeof(TypeLoadException), false },
-
- { "TestLoadAssembly", "PrivateClassSample", "PrivateClassSample", null, false },
- { "testloadassembly", "privateclasssample", "PrivateClassSample", typeof(TypeLoadException), false },
-
- { "TestLoadAssembly", "PublicClassNoDefaultConstructorSample", "PublicClassNoDefaultConstructorSample", typeof(MissingMethodException), false },
- { "testloadassembly", "publicclassnodefaultconstructorsample", "PublicClassNoDefaultConstructorSample", typeof(TypeLoadException), false },
-
- { "mscorlib", "System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", "", null, true }
- };
-
- [Theory]
- [MemberData(nameof(TestingCreateInstanceFromObjectHandleFullSignatureData))]
- public static void TestingCreateInstanceFromObjectHandleFullSignature(string physicalFileName, string assemblyFile, string type, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, string returnedFullNameType)
- {
- ObjectHandle oh = Activator.CreateInstanceFrom(assemblyFile: assemblyFile, typeName: type, ignoreCase: ignoreCase, bindingAttr: bindingAttr, binder: binder, args: args, culture: culture, activationAttributes: activationAttributes);
- CheckValidity(oh, returnedFullNameType);
- Assert.True(File.Exists(physicalFileName));
- }
-
- public static IEnumerable<object[]> TestingCreateInstanceFromObjectHandleFullSignatureData()
- {
- // string physicalFileName, string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, returnedFullNameType
- yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" };
- yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" };
- yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" };
- yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" };
-
- yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample" };
- yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample" };
- yield return new object[] { "TestLoadAssembly.dll", "TestLoadAssembly.dll", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample" };
- yield return new object[] { "TestLoadAssembly.dll", "testloadassembly.dll", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample" };
- }
-
- [Theory]
- [MemberData(nameof(TestingCreateInstanceObjectHandleFullSignatureData))]
- public static void TestingCreateInstanceObjectHandleFullSignature(string assemblyName, string type, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, string returnedFullNameType, bool returnNull)
- {
- ObjectHandle oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type, ignoreCase: ignoreCase, bindingAttr: bindingAttr, binder: binder, args: args, culture: culture, activationAttributes: activationAttributes);
- if (returnNull)
- {
- Assert.Null(oh);
- }
- else
- {
- CheckValidity(oh, returnedFullNameType);
- }
- }
-
- public static IEnumerable<object[]> TestingCreateInstanceObjectHandleFullSignatureData()
- {
- // string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, returnedFullNameType
- yield return new object[] { "TestLoadAssembly", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
- yield return new object[] { "testloadassembly", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
- yield return new object[] { "TestLoadAssembly", "PublicClassSample", false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
- yield return new object[] { "testloadassembly", "publicclasssample", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PublicClassSample" , false };
-
- yield return new object[] { "TestLoadAssembly", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
- yield return new object[] { "testloadassembly", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
- yield return new object[] { "TestLoadAssembly", "PrivateClassSample", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
- yield return new object[] { "testloadassembly", "privateclasssample", true, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[1] { 1 }, CultureInfo.InvariantCulture, null, "PrivateClassSample", false };
-
- yield return new object[] { null, typeof(PublicType).FullName, false, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, typeof(PublicType).FullName, false };
- yield return new object[] { null, typeof(PrivateType).FullName, false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, typeof(PrivateType).FullName, false };
-
- yield return new object[] { "mscorlib", "System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "", true };
- yield return new object[] { "mscorlib", "SyStEm.NULLABLE`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", true, BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "", true };
- }
-
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWinUISupported))]
- [PlatformSpecific(TestPlatforms.Windows)]
- [MemberData(nameof(TestingCreateInstanceObjectHandleFullSignatureWinRTData))]
- public static void TestingCreateInstanceObjectHandleFullSignatureWinRT(string assemblyName, string type, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, string returnedFullNameType)
- {
- ObjectHandle oh = Activator.CreateInstance(assemblyName: assemblyName, typeName: type, ignoreCase: ignoreCase, bindingAttr: bindingAttr, binder: binder, args: args, culture: culture, activationAttributes: activationAttributes);
- CheckValidity(oh, returnedFullNameType);
- }
-
- public static IEnumerable<object[]> TestingCreateInstanceObjectHandleFullSignatureWinRTData()
- {
- // string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes, returnedFullNameType
- yield return new object[] { "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime", "Windows.Foundation.Collections.StringMap", false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, new object[0], CultureInfo.InvariantCulture, null, "Windows.Foundation.Collections.StringMap" };
- }
-
- private static void CheckValidity(ObjectHandle instance, string expected)
- {
- Assert.NotNull(instance);
- Assert.Equal(expected, instance.Unwrap().GetType().FullName);
- }
-
- public class PublicType
- {
- public PublicType() { }
- }
-
- [Fact]
- public static void CreateInstanceAssemblyResolve()
- {
- RemoteExecutor.Invoke(() =>
- {
- AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) => Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), "TestLoadAssembly.dll"));
- Assert.Throws<FileLoadException>(() => Activator.CreateInstance(",,,,", "PublicClassSample"));
- }).Dispose();
- }
-
- [Fact]
- public void CreateInstance_TypeBuilder_ThrowsNotSupportedException()
- {
- AssemblyName assemblyName = new AssemblyName("Assembly");
- AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
- ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
- TypeBuilder typeBuilder = moduleBuilder.DefineType("Type", TypeAttributes.Public);
-
- Assert.Throws<ArgumentException>("type", () => Activator.CreateInstance(typeBuilder));
- Assert.Throws<NotSupportedException>(() => Activator.CreateInstance(typeBuilder, new object[0]));
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using System.Reflection;
+using Xunit;
+
+namespace System.Tests
+{
+ public static class ArgIteratorTests
+ {
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsArgIteratorSupported))]
+ public static void ArgIterator_GetRemainingCount_GetNextArg()
+ {
+ object[] result = GetAllArgs("a", "r", "g", "s", __arglist(true, "hello", 0.42));
+ Assert.Equal(new object[] {"a", "r", "g", "s", true, "hello", 0.42}, result);
+ }
+
+ private static object[] GetAllArgs(Object arg0, Object arg1, Object arg2, Object arg3, __arglist)
+ {
+ ArgIterator args = new ArgIterator(__arglist);
+ int argCount = args.GetRemainingCount() + 4;
+ object[] objArgs = new Object[argCount];
+
+ // Handle the hard-coded arguments
+ objArgs[0] = arg0;
+ objArgs[1] = arg1;
+ objArgs[2] = arg2;
+ objArgs[3] = arg3;
+
+ // Walk all of the args in the variable part of the argument list.
+ for (int i = 4; i < argCount; i++)
+ {
+ objArgs[i] = TypedReference.ToObject(args.GetNextArg());
+ }
+ args.End();
+
+ return objArgs;
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsArgIteratorSupported))]
+ public static void ArgIterator_GetNextArgType()
+ {
+ var types = new Type[]
+ {
+ typeof(string),
+ typeof(byte),
+ typeof(short),
+ typeof(long),
+ typeof(int),
+ typeof(float),
+ typeof(double),
+ typeof(DummyClass),
+ typeof(DummyStruct)
+ };
+
+ VerifyTypes(types, __arglist(
+ default(string),
+ default(byte),
+ default(short),
+ default(long),
+ default(int),
+ default(float),
+ default(double),
+ default(DummyClass),
+ default(DummyStruct)
+ ));
+ }
+
+ private class DummyClass { }
+ private struct DummyStruct { }
+
+ private static void VerifyTypes(Type[] types, __arglist)
+ {
+ ArgIterator args = new ArgIterator(__arglist);
+ int argCount = args.GetRemainingCount();
+ Assert.Equal(types.Length, argCount);
+
+ object[] objArgs = new Object[argCount];
+ for (int i = 0; i < argCount; i++)
+ {
+ RuntimeTypeHandle handle = args.GetNextArgType();
+ Type type = Type.GetTypeFromHandle(handle);
+ Assert.Equal(types[i], type);
+ args.GetNextArg(handle);
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsArgIteratorNotSupported))]
+ public static unsafe void ArgIterator_Throws_PlatformNotSupportedException()
+ {
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator(new RuntimeArgumentHandle()));
+ Assert.Throws<PlatformNotSupportedException>(() => {
+ fixed (void* p = "test")
+ {
+ new ArgIterator(new RuntimeArgumentHandle(), p);
+ }
+ });
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().End());
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().Equals(new object()));
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetHashCode());
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetNextArg());
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetNextArg(new RuntimeTypeHandle()));
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetNextArgType());
+ Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetRemainingCount());
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Globalization;
-using System.Reflection;
-using Xunit;
-
-namespace System.Tests
-{
- public static class ArgIteratorTests
- {
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsArgIteratorSupported))]
- public static void ArgIterator_GetRemainingCount_GetNextArg()
- {
- object[] result = GetAllArgs("a", "r", "g", "s", __arglist(true, "hello", 0.42));
- Assert.Equal(new object[] {"a", "r", "g", "s", true, "hello", 0.42}, result);
- }
-
- private static object[] GetAllArgs(Object arg0, Object arg1, Object arg2, Object arg3, __arglist)
- {
- ArgIterator args = new ArgIterator(__arglist);
- int argCount = args.GetRemainingCount() + 4;
- object[] objArgs = new Object[argCount];
-
- // Handle the hard-coded arguments
- objArgs[0] = arg0;
- objArgs[1] = arg1;
- objArgs[2] = arg2;
- objArgs[3] = arg3;
-
- // Walk all of the args in the variable part of the argument list.
- for (int i = 4; i < argCount; i++)
- {
- objArgs[i] = TypedReference.ToObject(args.GetNextArg());
- }
- args.End();
-
- return objArgs;
- }
-
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsArgIteratorSupported))]
- public static void ArgIterator_GetNextArgType()
- {
- var types = new Type[]
- {
- typeof(string),
- typeof(byte),
- typeof(short),
- typeof(long),
- typeof(int),
- typeof(float),
- typeof(double),
- typeof(DummyClass),
- typeof(DummyStruct)
- };
-
- VerifyTypes(types, __arglist(
- default(string),
- default(byte),
- default(short),
- default(long),
- default(int),
- default(float),
- default(double),
- default(DummyClass),
- default(DummyStruct)
- ));
- }
-
- private class DummyClass { }
- private struct DummyStruct { }
-
- private static void VerifyTypes(Type[] types, __arglist)
- {
- ArgIterator args = new ArgIterator(__arglist);
- int argCount = args.GetRemainingCount();
- Assert.Equal(types.Length, argCount);
-
- object[] objArgs = new Object[argCount];
- for (int i = 0; i < argCount; i++)
- {
- RuntimeTypeHandle handle = args.GetNextArgType();
- Type type = Type.GetTypeFromHandle(handle);
- Assert.Equal(types[i], type);
- args.GetNextArg(handle);
- }
- }
-
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsArgIteratorNotSupported))]
- public static unsafe void ArgIterator_Throws_PlatformNotSupportedException()
- {
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator(new RuntimeArgumentHandle()));
- Assert.Throws<PlatformNotSupportedException>(() => {
- fixed (void* p = "test")
- {
- new ArgIterator(new RuntimeArgumentHandle(), p);
- }
- });
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().End());
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().Equals(new object()));
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetHashCode());
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetNextArg());
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetNextArg(new RuntimeTypeHandle()));
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetNextArgType());
- Assert.Throws<PlatformNotSupportedException>(() => new ArgIterator().GetRemainingCount());
- }
- }
-}
AssertExtensions.Throws<ArgumentException>(null, () => new ArraySegment<T>(new T[10], 10, 1)); // Offset + count > array.Length
AssertExtensions.Throws<ArgumentException>(null, () => new ArraySegment<T>(new T[10], 9, 2)); // Offset + count > array.Length
}
+
+ [Fact]
+ public void CopyTo_Default_ThrowsInvalidOperationException()
+ {
+ // Source is default
+ Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).CopyTo(new T[0]));
+ Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).CopyTo(new T[0], 0));
+ Assert.Throws<InvalidOperationException>(() => ((ICollection<T>)default(ArraySegment<T>)).CopyTo(new T[0], 0));
+ Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).CopyTo(new ArraySegment<T>(new T[0])));
+
+ // Destination is default
+ Assert.Throws<InvalidOperationException>(() => new ArraySegment<T>(new T[0]).CopyTo(default(ArraySegment<T>)));
+ }
+
+ [Fact]
+ public void Empty()
+ {
+ ArraySegment<T> empty = ArraySegment<T>.Empty;
+
+ // Assert.NotEqual uses its own Comparer, when it is comparing IEnumerables it calls GetEnumerator()
+ // ArraySegment<T>.GetEnumerator() throws InvalidOperationException when the array is null and default() returns null
+ Assert.True(default(ArraySegment<T>) != empty);
+
+ // Check that two Empty invocations return equal ArraySegments.
+ Assert.Equal(empty, ArraySegment<T>.Empty);
+
+ // Check that two Empty invocations return ArraySegments with a cached empty array.
+ // An empty array is necessary to ensure that someone doesn't use the indexer to store data in the array Empty refers to.
+ Assert.Same(empty.Array, ArraySegment<T>.Empty.Array);
+ Assert.Equal(0, empty.Array.Length);
+ Assert.Equal(0, empty.Offset);
+ Assert.Equal(0, empty.Count);
+ }
+
+ [Fact]
+ public void GetEnumerator_TypeProperties()
+ {
+ var arraySegment = new ArraySegment<T>(new T[1], 0, 1);
+ var ienumerableoft = (IEnumerable<T>)arraySegment;
+ var ienumerable = (IEnumerable)arraySegment;
+
+ ArraySegment<T>.Enumerator enumerator = arraySegment.GetEnumerator();
+ Assert.IsType<ArraySegment<T>.Enumerator>(enumerator);
+ Assert.IsAssignableFrom<IEnumerator<T>>(enumerator);
+ Assert.IsAssignableFrom<IEnumerator>(enumerator);
+
+ IEnumerator<T> ienumeratoroft = ienumerableoft.GetEnumerator();
+ IEnumerator ienumerator = ienumerable.GetEnumerator();
+
+ Assert.Equal(enumerator.GetType(), ienumeratoroft.GetType());
+ Assert.Equal(ienumeratoroft.GetType(), ienumerator.GetType());
+ }
+
+ [Fact]
+ public void GetEnumerator_Default_ThrowsInvalidOperationException()
+ {
+ Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).GetEnumerator());
+ }
+
+ [Fact]
+ public void Slice_Default_ThrowsInvalidOperationException()
+ {
+ Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).Slice(0));
+ Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).Slice(0, 0));
+ }
+
+ [Fact]
+ public void ToArray_Default_ThrowsInvalidOperationException()
+ {
+ Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).ToArray());
+ }
+
+ [Fact]
+ public void ToArray_Empty_ReturnsSameArray()
+ {
+ T[] cachedArray = ArraySegment<T>.Empty.ToArray();
+ Assert.Same(cachedArray, ArraySegment<T>.Empty.ToArray());
+ Assert.Same(cachedArray, new ArraySegment<T>(new T[0]).ToArray());
+ Assert.Same(cachedArray, new ArraySegment<T>(new T[1], 0, 0).ToArray());
+ }
+
+ [Fact]
+ public void ToArray_NonEmptyArray_DoesNotReturnSameArray()
+ {
+ // Prevent a faulty implementation like `if (Count == 0) { return Array; }`
+ var emptyArraySegment = new ArraySegment<T>(new T[1], 0, 0);
+ Assert.NotSame(emptyArraySegment.Array, emptyArraySegment.ToArray());
+ }
+
+ [Fact]
+ public void Cast_FromNullArray_ReturnsDefault()
+ {
+ ArraySegment<T> fromNull = null;
+ Assert.Null(fromNull.Array);
+ Assert.Equal(0, fromNull.Offset);
+ Assert.Equal(0, fromNull.Count);
+
+ Assert.True(default(ArraySegment<T>) == null);
+ Assert.True(new ArraySegment<T>(Array.Empty<T>()) != null);
+ }
+
+ [Fact]
+ public void Cast_FromValidArray_ReturnsSegmentForWholeArray()
+ {
+ var array = new T[42];
+ ArraySegment<T> fromArray = array;
+ Assert.Same(array, fromArray.Array);
+ Assert.Equal(0, fromArray.Offset);
+ Assert.Equal(42, fromArray.Count);
+ }
}
public class ArraySegment_Tests_string : ArraySegment_Tests<string>
(enumerator as IEnumerator<int>).Reset();
}
}
+
+ [Theory]
+ [MemberData(nameof(Conversion_FromArray_TestData))]
+ public static void Conversion_FromArray(int[] array)
+ {
+ ArraySegment<int> implicitlyConverted = array;
+ ArraySegment<int> explicitlyConverted = (ArraySegment<int>)array;
+
+ var expected = new ArraySegment<int>(array);
+ Assert.Equal(expected, implicitlyConverted);
+ Assert.Equal(expected, explicitlyConverted);
+ }
+
+ public static IEnumerable<object[]> Conversion_FromArray_TestData()
+ {
+ yield return new object[] { new int[0] };
+ yield return new object[] { new int[1] };
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void CopyTo(ArraySegment<int> arraySegment)
+ {
+ const int CopyPadding = 5;
+ const int DestinationSegmentPadding = 3;
+
+ int count = arraySegment.Count;
+
+ var destinationModel = new int[count + 2 * CopyPadding];
+
+ // CopyTo(T[])
+ CopyAndInvoke(destinationModel, destination =>
+ {
+ arraySegment.CopyTo(destination);
+
+ Assert.Equal(Enumerable.Repeat(default(int), 2 * CopyPadding), destination.Skip(count));
+
+ Assert.Equal(arraySegment, destination.Take(count));
+ });
+
+ // CopyTo(T[], int)
+ CopyAndInvoke(destinationModel, destination =>
+ {
+ arraySegment.CopyTo(destination, CopyPadding);
+
+ Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Take(CopyPadding));
+ Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Skip(CopyPadding + count));
+
+ Assert.Equal(arraySegment, destination.Skip(CopyPadding).Take(count));
+ });
+
+ // ICollection<T>.CopyTo(T[], int)
+ CopyAndInvoke(destinationModel, destination =>
+ {
+ ((ICollection<int>)arraySegment).CopyTo(destination, CopyPadding);
+
+ Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Take(CopyPadding));
+ Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Skip(CopyPadding + count));
+
+ Assert.Equal(arraySegment, destination.Skip(CopyPadding).Take(count));
+ });
+
+ // CopyTo(ArraySegment<T>)
+ CopyAndInvoke(destinationModel, destination =>
+ {
+ // We want to make sure this overload is handling edge cases correctly, like ArraySegments that
+ // do not begin at the array's start, do not end at the array's end, or have a bigger count than
+ // the source ArraySegment. Construct an ArraySegment that will test all of these conditions.
+ int destinationIndex = DestinationSegmentPadding;
+ int destinationCount = destination.Length - 2 * DestinationSegmentPadding;
+ var destinationSegment = new ArraySegment<int>(destination, destinationIndex, destinationCount);
+
+ arraySegment.CopyTo(destinationSegment);
+
+ Assert.Equal(Enumerable.Repeat(default(int), destinationIndex), destination.Take(destinationIndex));
+ int remainder = destination.Length - destinationIndex - count;
+ Assert.Equal(Enumerable.Repeat(default(int), remainder), destination.Skip(destinationIndex + count));
+
+ Assert.Equal(arraySegment, destination.Skip(destinationIndex).Take(count));
+ });
+ }
+
+ private static void CopyAndInvoke<T>(T[] array, Action<T[]> action) => action(array.ToArray());
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void CopyTo_Invalid(ArraySegment<int> arraySegment)
+ {
+ int count = arraySegment.Count;
+
+ // ArraySegment.CopyTo calls Array.Copy internally, so the exception parameter names come from there.
+
+ // Destination is null
+ AssertExtensions.Throws<ArgumentNullException>("destinationArray", () => arraySegment.CopyTo(null));
+ AssertExtensions.Throws<ArgumentNullException>("destinationArray", () => arraySegment.CopyTo(null, 0));
+
+ // Destination index not within range
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("destinationIndex", () => arraySegment.CopyTo(new int[0], -1));
+
+ // Destination array too small arraySegment.Count + destinationIndex > destinationArray.Length
+ AssertExtensions.Throws<ArgumentException>("destinationArray", () => arraySegment.CopyTo(new int[arraySegment.Count * 2], arraySegment.Count + 1));
+
+ if (arraySegment.Any())
+ {
+ // Destination not large enough
+ AssertExtensions.Throws<ArgumentException>("destinationArray", () => arraySegment.CopyTo(new int[count - 1]));
+ AssertExtensions.Throws<ArgumentException>("destinationArray", () => arraySegment.CopyTo(new int[count - 1], 0));
+ AssertExtensions.Throws<ArgumentException>("destination", null, () => arraySegment.CopyTo(new ArraySegment<int>(new int[count - 1])));
+
+ // Don't write beyond the limits of the destination in cases where source.Count > destination.Count
+ AssertExtensions.Throws<ArgumentException>("destination", null, () => arraySegment.CopyTo(new ArraySegment<int>(new int[count], 1, 0))); // destination.Array can't fit source at destination.Offset
+ AssertExtensions.Throws<ArgumentException>("destination", null, () => arraySegment.CopyTo(new ArraySegment<int>(new int[count], 0, count - 1))); // destination.Array can fit source at destination.Offset, but destination can't
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void GetEnumerator(ArraySegment<int> arraySegment)
+ {
+ int[] array = arraySegment.Array;
+ int index = arraySegment.Offset;
+ int count = arraySegment.Count;
+
+ ArraySegment<int>.Enumerator enumerator = arraySegment.GetEnumerator();
+
+ var actual = new List<int>();
+
+ while (enumerator.MoveNext())
+ {
+ actual.Add(enumerator.Current);
+ }
+
+ // After MoveNext returns false once, it should return false the second time.
+ Assert.False(enumerator.MoveNext());
+
+ IEnumerable<int> expected = array.Skip(index).Take(count);
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void GetEnumerator_Dispose(ArraySegment<int> arraySegment)
+ {
+ int[] array = arraySegment.Array;
+ int index = arraySegment.Offset;
+
+ ArraySegment<int>.Enumerator enumerator = arraySegment.GetEnumerator();
+
+ bool expected = arraySegment.Count > 0;
+
+ // Dispose shouldn't do anything. Call it twice and then assert like nothing happened.
+ enumerator.Dispose();
+ enumerator.Dispose();
+
+ Assert.Equal(expected, enumerator.MoveNext());
+ if (expected)
+ {
+ Assert.Equal(array[index], enumerator.Current);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void GetEnumerator_Reset(ArraySegment<int> arraySegment)
+ {
+ int[] array = arraySegment.Array;
+ int index = arraySegment.Offset;
+ int count = arraySegment.Count;
+
+ var enumerator = (IEnumerator<int>)arraySegment.GetEnumerator();
+
+ int[] expected = array.Skip(index).Take(count).ToArray();
+
+ // Reset at a variety of different positions to ensure the implementation
+ // isn't something like `position -= CONSTANT`.
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < i; j++)
+ {
+ if (enumerator.MoveNext())
+ {
+ Assert.Equal(expected[j], enumerator.Current);
+ }
+ }
+
+ enumerator.Reset();
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void GetEnumerator_Invalid(ArraySegment<int> arraySegment)
+ {
+ ArraySegment<int>.Enumerator enumerator = arraySegment.GetEnumerator();
+
+ // Before beginning
+ Assert.Throws<InvalidOperationException>(() => enumerator.Current);
+ Assert.Throws<InvalidOperationException>(() => ((IEnumerator<int>)enumerator).Current);
+ Assert.Throws<InvalidOperationException>(() => ((IEnumerator)enumerator).Current);
+
+ while (enumerator.MoveNext()) ;
+
+ // After end
+ Assert.Throws<InvalidOperationException>(() => enumerator.Current);
+ Assert.Throws<InvalidOperationException>(() => ((IEnumerator<int>)enumerator).Current);
+ Assert.Throws<InvalidOperationException>(() => ((IEnumerator)enumerator).Current);
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void GetSetItem_InRange(ArraySegment<int> arraySegment)
+ {
+ int[] array = arraySegment.Array;
+ int index = arraySegment.Offset;
+ int count = arraySegment.Count;
+
+ int[] expected = array.Skip(index).Take(count).ToArray();
+
+ for (int i = 0; i < count; i++)
+ {
+ Assert.Equal(expected[i], arraySegment[i]);
+ Assert.Equal(expected[i], ((IList<int>)arraySegment)[i]);
+ Assert.Equal(expected[i], ((IReadOnlyList<int>)arraySegment)[i]);
+ }
+
+ var r = new Random(0);
+
+ for (int i = 0; i < count; i++)
+ {
+ int next = r.Next(int.MinValue, int.MaxValue);
+
+ // When we modify the underlying array, the indexer should return the updated values.
+ array[arraySegment.Offset + i] ^= next;
+ Assert.Equal(expected[i] ^ next, arraySegment[i]);
+
+ // When the indexer's set method is called, the underlying array should be modified.
+ arraySegment[i] ^= next;
+ Assert.Equal(expected[i], array[arraySegment.Offset + i]);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void GetSetItem_NotInRange_Invalid(ArraySegment<int> arraySegment)
+ {
+ int[] array = arraySegment.Array;
+
+ // Before array start
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset - 1]);
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset - 1] = default(int));
+
+ // After array start (if Offset > 0), before start
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-1]);
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-1] = default(int));
+
+ // Before array end (if Offset + Count < Array.Length), after end
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[arraySegment.Count]);
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[arraySegment.Count] = default(int));
+
+ // After array end
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset + array.Length]);
+ Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset + array.Length] = default(int));
+ }
+
+ [Theory]
+ [MemberData(nameof(Slice_TestData))]
+ public static void Slice(ArraySegment<int> arraySegment, int index, int count)
+ {
+ var expected = new ArraySegment<int>(arraySegment.Array, arraySegment.Offset + index, count);
+
+ if (index + count == arraySegment.Count)
+ {
+ Assert.Equal(expected, arraySegment.Slice(index));
+ }
+
+ Assert.Equal(expected, arraySegment.Slice(index, count));
+ }
+
+ public static IEnumerable<object[]> Slice_TestData()
+ {
+ IEnumerable<ArraySegment<int>> arraySegments = ArraySegment_TestData().Select(array => array.Single()).Cast<ArraySegment<int>>();
+
+ foreach (ArraySegment<int> arraySegment in arraySegments)
+ {
+ yield return new object[] { arraySegment, 0, 0 }; // Preserve start, no items
+ yield return new object[] { arraySegment, 0, arraySegment.Count }; // Preserve start, preserve count (noop)
+ yield return new object[] { arraySegment, arraySegment.Count, 0 }; // Start at end, no items
+
+ if (arraySegment.Any())
+ {
+ yield return new object[] { arraySegment, 1, 0 }; // Start at middle or end, no items
+ yield return new object[] { arraySegment, 1, arraySegment.Count - 1 }; // Start at middle or end, rest of items
+ yield return new object[] { arraySegment, arraySegment.Count - 1, 1 }; // Preserve start or start at middle, one item
+ }
+
+ yield return new object[] { arraySegment, 0, arraySegment.Count / 2 }; // Preserve start, multiple items, end at middle
+ yield return new object[] { arraySegment, arraySegment.Count / 2, arraySegment.Count / 2 }; // Start at middle, multiple items, end at middle (due to integer division truncation) or preserve end
+ yield return new object[] { arraySegment, arraySegment.Count / 4, arraySegment.Count / 2 }; // Start at middle, multiple items, end at middle
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(Slice_Invalid_TestData))]
+ public static void Slice_Invalid(ArraySegment<int> arraySegment, int index, int count)
+ {
+ if (index + count == arraySegment.Count)
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => arraySegment.Slice(index));
+ }
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => arraySegment.Slice(index, count));
+ }
+
+ public static IEnumerable<object[]> Slice_Invalid_TestData()
+ {
+ var arraySegment = new ArraySegment<int>(new int[3], offset: 1, count: 1);
+
+ yield return new object[] { arraySegment, -arraySegment.Offset, arraySegment.Offset };
+ yield return new object[] { arraySegment, -arraySegment.Offset, arraySegment.Offset + arraySegment.Count };
+ yield return new object[] { arraySegment, -arraySegment.Offset, arraySegment.Array.Length };
+ yield return new object[] { arraySegment, 0, arraySegment.Array.Length - arraySegment.Offset };
+ yield return new object[] { arraySegment, arraySegment.Count, arraySegment.Array.Length - arraySegment.Offset - arraySegment.Count };
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySegment_TestData))]
+ public static void ToArray(ArraySegment<int> arraySegment)
+ {
+ // ToList is called here so we copy the data and raise an assert if ToArray modifies the underlying array.
+ List<int> expected = arraySegment.Array.Skip(arraySegment.Offset).Take(arraySegment.Count).ToList();
+ Assert.Equal(expected, arraySegment.ToArray());
+ }
+
+ public static IEnumerable<object[]> ArraySegment_TestData()
+ {
+ var arraySegments = new (int[] array, int index, int count)[]
+ {
+ (array: new int[0], index: 0, 0), // Empty array
+ (array: new[] { 3, 4, 5, 6 }, index: 0, count: 4), // Full span of non-empty array
+ (array: new[] { 3, 4, 5, 6 }, index: 0, count: 3), // Starts at beginning, ends in middle
+ (array: new[] { 3, 4, 5, 6 }, index: 1, count: 3), // Starts in middle, ends at end
+ (array: new[] { 3, 4, 5, 6 }, index: 1, count: 2), // Starts in middle, ends in middle
+ (array: new[] { 3, 4, 5, 6 }, index: 1, count: 0) // Non-empty array, count == 0
+ };
+
+ return arraySegments.Select(aseg => new object[] { new ArraySegment<int>(aseg.array, aseg.index, aseg.count) });
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using Xunit;
-
-namespace System.Tests
-{
- public abstract partial class ArraySegment_Tests<T>
- {
- [Fact]
- public void CopyTo_Default_ThrowsInvalidOperationException()
- {
- // Source is default
- Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).CopyTo(new T[0]));
- Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).CopyTo(new T[0], 0));
- Assert.Throws<InvalidOperationException>(() => ((ICollection<T>)default(ArraySegment<T>)).CopyTo(new T[0], 0));
- Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).CopyTo(new ArraySegment<T>(new T[0])));
-
- // Destination is default
- Assert.Throws<InvalidOperationException>(() => new ArraySegment<T>(new T[0]).CopyTo(default(ArraySegment<T>)));
- }
-
- [Fact]
- public void Empty()
- {
- ArraySegment<T> empty = ArraySegment<T>.Empty;
-
- // Assert.NotEqual uses its own Comparer, when it is comparing IEnumerables it calls GetEnumerator()
- // ArraySegment<T>.GetEnumerator() throws InvalidOperationException when the array is null and default() returns null
- Assert.True(default(ArraySegment<T>) != empty);
-
- // Check that two Empty invocations return equal ArraySegments.
- Assert.Equal(empty, ArraySegment<T>.Empty);
-
- // Check that two Empty invocations return ArraySegments with a cached empty array.
- // An empty array is necessary to ensure that someone doesn't use the indexer to store data in the array Empty refers to.
- Assert.Same(empty.Array, ArraySegment<T>.Empty.Array);
- Assert.Equal(0, empty.Array.Length);
- Assert.Equal(0, empty.Offset);
- Assert.Equal(0, empty.Count);
- }
-
- [Fact]
- public void GetEnumerator_TypeProperties()
- {
- var arraySegment = new ArraySegment<T>(new T[1], 0, 1);
- var ienumerableoft = (IEnumerable<T>)arraySegment;
- var ienumerable = (IEnumerable)arraySegment;
-
- ArraySegment<T>.Enumerator enumerator = arraySegment.GetEnumerator();
- Assert.IsType<ArraySegment<T>.Enumerator>(enumerator);
- Assert.IsAssignableFrom<IEnumerator<T>>(enumerator);
- Assert.IsAssignableFrom<IEnumerator>(enumerator);
-
- IEnumerator<T> ienumeratoroft = ienumerableoft.GetEnumerator();
- IEnumerator ienumerator = ienumerable.GetEnumerator();
-
- Assert.Equal(enumerator.GetType(), ienumeratoroft.GetType());
- Assert.Equal(ienumeratoroft.GetType(), ienumerator.GetType());
- }
-
- [Fact]
- public void GetEnumerator_Default_ThrowsInvalidOperationException()
- {
- Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).GetEnumerator());
- }
-
- [Fact]
- public void Slice_Default_ThrowsInvalidOperationException()
- {
- Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).Slice(0));
- Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).Slice(0, 0));
- }
-
- [Fact]
- public void ToArray_Default_ThrowsInvalidOperationException()
- {
- Assert.Throws<InvalidOperationException>(() => default(ArraySegment<T>).ToArray());
- }
-
- [Fact]
- public void ToArray_Empty_ReturnsSameArray()
- {
- T[] cachedArray = ArraySegment<T>.Empty.ToArray();
- Assert.Same(cachedArray, ArraySegment<T>.Empty.ToArray());
- Assert.Same(cachedArray, new ArraySegment<T>(new T[0]).ToArray());
- Assert.Same(cachedArray, new ArraySegment<T>(new T[1], 0, 0).ToArray());
- }
-
- [Fact]
- public void ToArray_NonEmptyArray_DoesNotReturnSameArray()
- {
- // Prevent a faulty implementation like `if (Count == 0) { return Array; }`
- var emptyArraySegment = new ArraySegment<T>(new T[1], 0, 0);
- Assert.NotSame(emptyArraySegment.Array, emptyArraySegment.ToArray());
- }
-
- [Fact]
- public void Cast_FromNullArray_ReturnsDefault()
- {
- ArraySegment<T> fromNull = null;
- Assert.Null(fromNull.Array);
- Assert.Equal(0, fromNull.Offset);
- Assert.Equal(0, fromNull.Count);
-
- Assert.True(default(ArraySegment<T>) == null);
- Assert.True(new ArraySegment<T>(Array.Empty<T>()) != null);
- }
-
- [Fact]
- public void Cast_FromValidArray_ReturnsSegmentForWholeArray()
- {
- var array = new T[42];
- ArraySegment<T> fromArray = array;
- Assert.Same(array, fromArray.Array);
- Assert.Equal(0, fromArray.Offset);
- Assert.Equal(42, fromArray.Count);
- }
- }
-
- public static partial class ArraySegment_Tests
- {
- [Theory]
- [MemberData(nameof(Conversion_FromArray_TestData))]
- public static void Conversion_FromArray(int[] array)
- {
- ArraySegment<int> implicitlyConverted = array;
- ArraySegment<int> explicitlyConverted = (ArraySegment<int>)array;
-
- var expected = new ArraySegment<int>(array);
- Assert.Equal(expected, implicitlyConverted);
- Assert.Equal(expected, explicitlyConverted);
- }
-
- public static IEnumerable<object[]> Conversion_FromArray_TestData()
- {
- yield return new object[] { new int[0] };
- yield return new object[] { new int[1] };
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void CopyTo(ArraySegment<int> arraySegment)
- {
- const int CopyPadding = 5;
- const int DestinationSegmentPadding = 3;
-
- int count = arraySegment.Count;
-
- var destinationModel = new int[count + 2 * CopyPadding];
-
- // CopyTo(T[])
- CopyAndInvoke(destinationModel, destination =>
- {
- arraySegment.CopyTo(destination);
-
- Assert.Equal(Enumerable.Repeat(default(int), 2 * CopyPadding), destination.Skip(count));
-
- Assert.Equal(arraySegment, destination.Take(count));
- });
-
- // CopyTo(T[], int)
- CopyAndInvoke(destinationModel, destination =>
- {
- arraySegment.CopyTo(destination, CopyPadding);
-
- Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Take(CopyPadding));
- Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Skip(CopyPadding + count));
-
- Assert.Equal(arraySegment, destination.Skip(CopyPadding).Take(count));
- });
-
- // ICollection<T>.CopyTo(T[], int)
- CopyAndInvoke(destinationModel, destination =>
- {
- ((ICollection<int>)arraySegment).CopyTo(destination, CopyPadding);
-
- Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Take(CopyPadding));
- Assert.Equal(Enumerable.Repeat(default(int), CopyPadding), destination.Skip(CopyPadding + count));
-
- Assert.Equal(arraySegment, destination.Skip(CopyPadding).Take(count));
- });
-
- // CopyTo(ArraySegment<T>)
- CopyAndInvoke(destinationModel, destination =>
- {
- // We want to make sure this overload is handling edge cases correctly, like ArraySegments that
- // do not begin at the array's start, do not end at the array's end, or have a bigger count than
- // the source ArraySegment. Construct an ArraySegment that will test all of these conditions.
- int destinationIndex = DestinationSegmentPadding;
- int destinationCount = destination.Length - 2 * DestinationSegmentPadding;
- var destinationSegment = new ArraySegment<int>(destination, destinationIndex, destinationCount);
-
- arraySegment.CopyTo(destinationSegment);
-
- Assert.Equal(Enumerable.Repeat(default(int), destinationIndex), destination.Take(destinationIndex));
- int remainder = destination.Length - destinationIndex - count;
- Assert.Equal(Enumerable.Repeat(default(int), remainder), destination.Skip(destinationIndex + count));
-
- Assert.Equal(arraySegment, destination.Skip(destinationIndex).Take(count));
- });
- }
-
- private static void CopyAndInvoke<T>(T[] array, Action<T[]> action) => action(array.ToArray());
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void CopyTo_Invalid(ArraySegment<int> arraySegment)
- {
- int count = arraySegment.Count;
-
- // ArraySegment.CopyTo calls Array.Copy internally, so the exception parameter names come from there.
-
- // Destination is null
- AssertExtensions.Throws<ArgumentNullException>("destinationArray", () => arraySegment.CopyTo(null));
- AssertExtensions.Throws<ArgumentNullException>("destinationArray", () => arraySegment.CopyTo(null, 0));
-
- // Destination index not within range
- AssertExtensions.Throws<ArgumentOutOfRangeException>("destinationIndex", () => arraySegment.CopyTo(new int[0], -1));
-
- // Destination array too small arraySegment.Count + destinationIndex > destinationArray.Length
- AssertExtensions.Throws<ArgumentException>("destinationArray", () => arraySegment.CopyTo(new int[arraySegment.Count * 2], arraySegment.Count + 1));
-
- if (arraySegment.Any())
- {
- // Destination not large enough
- AssertExtensions.Throws<ArgumentException>("destinationArray", () => arraySegment.CopyTo(new int[count - 1]));
- AssertExtensions.Throws<ArgumentException>("destinationArray", () => arraySegment.CopyTo(new int[count - 1], 0));
- AssertExtensions.Throws<ArgumentException>("destination", null, () => arraySegment.CopyTo(new ArraySegment<int>(new int[count - 1])));
-
- // Don't write beyond the limits of the destination in cases where source.Count > destination.Count
- AssertExtensions.Throws<ArgumentException>("destination", null, () => arraySegment.CopyTo(new ArraySegment<int>(new int[count], 1, 0))); // destination.Array can't fit source at destination.Offset
- AssertExtensions.Throws<ArgumentException>("destination", null, () => arraySegment.CopyTo(new ArraySegment<int>(new int[count], 0, count - 1))); // destination.Array can fit source at destination.Offset, but destination can't
- }
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void GetEnumerator(ArraySegment<int> arraySegment)
- {
- int[] array = arraySegment.Array;
- int index = arraySegment.Offset;
- int count = arraySegment.Count;
-
- ArraySegment<int>.Enumerator enumerator = arraySegment.GetEnumerator();
-
- var actual = new List<int>();
-
- while (enumerator.MoveNext())
- {
- actual.Add(enumerator.Current);
- }
-
- // After MoveNext returns false once, it should return false the second time.
- Assert.False(enumerator.MoveNext());
-
- IEnumerable<int> expected = array.Skip(index).Take(count);
- Assert.Equal(expected, actual);
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void GetEnumerator_Dispose(ArraySegment<int> arraySegment)
- {
- int[] array = arraySegment.Array;
- int index = arraySegment.Offset;
-
- ArraySegment<int>.Enumerator enumerator = arraySegment.GetEnumerator();
-
- bool expected = arraySegment.Count > 0;
-
- // Dispose shouldn't do anything. Call it twice and then assert like nothing happened.
- enumerator.Dispose();
- enumerator.Dispose();
-
- Assert.Equal(expected, enumerator.MoveNext());
- if (expected)
- {
- Assert.Equal(array[index], enumerator.Current);
- }
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void GetEnumerator_Reset(ArraySegment<int> arraySegment)
- {
- int[] array = arraySegment.Array;
- int index = arraySegment.Offset;
- int count = arraySegment.Count;
-
- var enumerator = (IEnumerator<int>)arraySegment.GetEnumerator();
-
- int[] expected = array.Skip(index).Take(count).ToArray();
-
- // Reset at a variety of different positions to ensure the implementation
- // isn't something like `position -= CONSTANT`.
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < i; j++)
- {
- if (enumerator.MoveNext())
- {
- Assert.Equal(expected[j], enumerator.Current);
- }
- }
-
- enumerator.Reset();
- }
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void GetEnumerator_Invalid(ArraySegment<int> arraySegment)
- {
- ArraySegment<int>.Enumerator enumerator = arraySegment.GetEnumerator();
-
- // Before beginning
- Assert.Throws<InvalidOperationException>(() => enumerator.Current);
- Assert.Throws<InvalidOperationException>(() => ((IEnumerator<int>)enumerator).Current);
- Assert.Throws<InvalidOperationException>(() => ((IEnumerator)enumerator).Current);
-
- while (enumerator.MoveNext()) ;
-
- // After end
- Assert.Throws<InvalidOperationException>(() => enumerator.Current);
- Assert.Throws<InvalidOperationException>(() => ((IEnumerator<int>)enumerator).Current);
- Assert.Throws<InvalidOperationException>(() => ((IEnumerator)enumerator).Current);
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void GetSetItem_InRange(ArraySegment<int> arraySegment)
- {
- int[] array = arraySegment.Array;
- int index = arraySegment.Offset;
- int count = arraySegment.Count;
-
- int[] expected = array.Skip(index).Take(count).ToArray();
-
- for (int i = 0; i < count; i++)
- {
- Assert.Equal(expected[i], arraySegment[i]);
- Assert.Equal(expected[i], ((IList<int>)arraySegment)[i]);
- Assert.Equal(expected[i], ((IReadOnlyList<int>)arraySegment)[i]);
- }
-
- var r = new Random(0);
-
- for (int i = 0; i < count; i++)
- {
- int next = r.Next(int.MinValue, int.MaxValue);
-
- // When we modify the underlying array, the indexer should return the updated values.
- array[arraySegment.Offset + i] ^= next;
- Assert.Equal(expected[i] ^ next, arraySegment[i]);
-
- // When the indexer's set method is called, the underlying array should be modified.
- arraySegment[i] ^= next;
- Assert.Equal(expected[i], array[arraySegment.Offset + i]);
- }
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void GetSetItem_NotInRange_Invalid(ArraySegment<int> arraySegment)
- {
- int[] array = arraySegment.Array;
-
- // Before array start
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset - 1]);
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset - 1] = default(int));
-
- // After array start (if Offset > 0), before start
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-1]);
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-1] = default(int));
-
- // Before array end (if Offset + Count < Array.Length), after end
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[arraySegment.Count]);
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[arraySegment.Count] = default(int));
-
- // After array end
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset + array.Length]);
- Assert.Throws<ArgumentOutOfRangeException>(() => arraySegment[-arraySegment.Offset + array.Length] = default(int));
- }
-
- [Theory]
- [MemberData(nameof(Slice_TestData))]
- public static void Slice(ArraySegment<int> arraySegment, int index, int count)
- {
- var expected = new ArraySegment<int>(arraySegment.Array, arraySegment.Offset + index, count);
-
- if (index + count == arraySegment.Count)
- {
- Assert.Equal(expected, arraySegment.Slice(index));
- }
-
- Assert.Equal(expected, arraySegment.Slice(index, count));
- }
-
- public static IEnumerable<object[]> Slice_TestData()
- {
- IEnumerable<ArraySegment<int>> arraySegments = ArraySegment_TestData().Select(array => array.Single()).Cast<ArraySegment<int>>();
-
- foreach (ArraySegment<int> arraySegment in arraySegments)
- {
- yield return new object[] { arraySegment, 0, 0 }; // Preserve start, no items
- yield return new object[] { arraySegment, 0, arraySegment.Count }; // Preserve start, preserve count (noop)
- yield return new object[] { arraySegment, arraySegment.Count, 0 }; // Start at end, no items
-
- if (arraySegment.Any())
- {
- yield return new object[] { arraySegment, 1, 0 }; // Start at middle or end, no items
- yield return new object[] { arraySegment, 1, arraySegment.Count - 1 }; // Start at middle or end, rest of items
- yield return new object[] { arraySegment, arraySegment.Count - 1, 1 }; // Preserve start or start at middle, one item
- }
-
- yield return new object[] { arraySegment, 0, arraySegment.Count / 2 }; // Preserve start, multiple items, end at middle
- yield return new object[] { arraySegment, arraySegment.Count / 2, arraySegment.Count / 2 }; // Start at middle, multiple items, end at middle (due to integer division truncation) or preserve end
- yield return new object[] { arraySegment, arraySegment.Count / 4, arraySegment.Count / 2 }; // Start at middle, multiple items, end at middle
- }
- }
-
- [Theory]
- [MemberData(nameof(Slice_Invalid_TestData))]
- public static void Slice_Invalid(ArraySegment<int> arraySegment, int index, int count)
- {
- if (index + count == arraySegment.Count)
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => arraySegment.Slice(index));
- }
-
- AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => arraySegment.Slice(index, count));
- }
-
- public static IEnumerable<object[]> Slice_Invalid_TestData()
- {
- var arraySegment = new ArraySegment<int>(new int[3], offset: 1, count: 1);
-
- yield return new object[] { arraySegment, -arraySegment.Offset, arraySegment.Offset };
- yield return new object[] { arraySegment, -arraySegment.Offset, arraySegment.Offset + arraySegment.Count };
- yield return new object[] { arraySegment, -arraySegment.Offset, arraySegment.Array.Length };
- yield return new object[] { arraySegment, 0, arraySegment.Array.Length - arraySegment.Offset };
- yield return new object[] { arraySegment, arraySegment.Count, arraySegment.Array.Length - arraySegment.Offset - arraySegment.Count };
- }
-
- [Theory]
- [MemberData(nameof(ArraySegment_TestData))]
- public static void ToArray(ArraySegment<int> arraySegment)
- {
- // ToList is called here so we copy the data and raise an assert if ToArray modifies the underlying array.
- List<int> expected = arraySegment.Array.Skip(arraySegment.Offset).Take(arraySegment.Count).ToList();
- Assert.Equal(expected, arraySegment.ToArray());
- }
-
- public static IEnumerable<object[]> ArraySegment_TestData()
- {
- var arraySegments = new (int[] array, int index, int count)[]
- {
- (array: new int[0], index: 0, 0), // Empty array
- (array: new[] { 3, 4, 5, 6 }, index: 0, count: 4), // Full span of non-empty array
- (array: new[] { 3, 4, 5, 6 }, index: 0, count: 3), // Starts at beginning, ends in middle
- (array: new[] { 3, 4, 5, 6 }, index: 1, count: 3), // Starts in middle, ends at end
- (array: new[] { 3, 4, 5, 6 }, index: 1, count: 2), // Starts in middle, ends in middle
- (array: new[] { 3, 4, 5, 6 }, index: 1, count: 0) // Non-empty array, count == 0
- };
-
- return arraySegments.Select(aseg => new object[] { new ArraySegment<int>(aseg.array, aseg.index, aseg.count) });
- }
- }
-}
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
using Xunit;
namespace System.Tests
{
- public partial class ArrayTests
+ public class ArrayTests
{
[Fact]
public static void IList_GetSetItem()
Array.Reverse((Array)new int*[1]);
}
+ public static IEnumerable<object[]> Fill_Generic_TestData()
+ {
+ var data = Enumerable.Empty<object[]>();
+
+ var r = new Random(0x051778f7);
+ int[] lengths = { 0, 1, 2, 3, 5, 8, 13 };
+
+ foreach (int length in lengths)
+ {
+ IEnumerable<int> source = Enumerable.Range(1, length).Select(_ => r.Next());
+
+ data = data.Concat(GenerateFillData(source, r.Next(), i => i))
+ .Concat(GenerateFillData(source, r.Next(), i => unchecked((byte)i)))
+ .Concat(GenerateFillData(source, r.Next(), i => unchecked((short)i)))
+ .Concat(GenerateFillData(source, r.Next(), i => (long)i))
+ .Concat(GenerateFillData(source, r.Next(), i => new StrongBox<int>(i)))
+ .Concat(GenerateFillData(source, r.Next(), i => i.ToString()))
+ .Concat(GenerateFillData(source, r.Next(), i => unchecked((ByteEnum)i)))
+ .Concat(GenerateFillData(source, r.Next(), i => unchecked((Int16Enum)i)))
+ .Concat(GenerateFillData(source, r.Next(), i => (Int32Enum)i))
+ .Concat(GenerateFillData(source, r.Next(), i => (Int64Enum)i))
+ .Concat(GenerateFillData(source, r.Next(), i => new object()));
+ }
+
+ return data;
+ }
+
+ public static IEnumerable<object[]> GenerateFillData<TSource, TResult>(IEnumerable<TSource> source, TSource seed, Func<TSource, TResult> transform)
+ {
+ int count = source.Count();
+ TResult repeatedValue = transform(seed);
+ // Force evaluation so neither `source` or `transform` are re-run if the sequence is enumerated more than once.
+ IEnumerable<TResult> transformed = source.Select(transform).ToList();
+
+ yield return new object[] { transformed, repeatedValue, 0, count }; // Fill the entire array.
+ yield return new object[] { transformed, repeatedValue, 0, count / 2 }; // Fill the beginning of the array.
+ yield return new object[] { transformed, repeatedValue, count / 2, count / 2 }; // Fill the end of the array, assuming `length` is even.
+ yield return new object[] { transformed, repeatedValue, count / 4, count / 2 }; // Fill the middle of the array.
+ yield return new object[] { transformed, repeatedValue, count, 0 }; // Fill nothing.
+ }
+
+ [Theory]
+ [MemberData(nameof(Fill_Generic_TestData))]
+ public static void Fill_Generic<T>(IEnumerable<T> source, T value, int startIndex, int count)
+ {
+ if (startIndex == 0 && count == source.Count())
+ {
+ T[] array = source.ToArray();
+ Array.Fill(array, value);
+ Assert.Equal(Enumerable.Repeat(value, count), array);
+ }
+
+ {
+ T[] array = source.ToArray();
+
+ // Before calling Fill, we want to capture the segments before/after the filled region.
+ // We want to ensure that in addition to filling in what it's supposed to, Fill does
+ // not touch the adjacent segments.
+ T[] before = source.Take(startIndex).ToArray();
+ T[] after = source.Skip(startIndex + count).ToArray();
+
+ Array.Fill(array, value, startIndex, count);
+
+ Assert.Equal(before, array.Take(startIndex));
+ Assert.Equal(Enumerable.Repeat(value, count), array.Skip(startIndex).Take(count));
+ Assert.Equal(after, array.Skip(startIndex + count));
+ }
+ }
+
+ [Fact]
+ public void Fill_NullArray_ThrowsArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Fill(null, 1));
+ AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Fill(null, 1, 0, 0));
+ }
+
+ [Theory]
+ [InlineData(-1)]
+ [InlineData(2)]
+ public void Fill_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex)
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("startIndex", () => Array.Fill(new string[1], "", startIndex, 0));
+ }
+
+ [Theory]
+ [InlineData(1, 0, -1)]
+ [InlineData(0, 0, 1)]
+ [InlineData(3, 3, 1)]
+ [InlineData(3, 2, 2)]
+ [InlineData(3, 1, 3)]
+ [InlineData(3, 0, 4)]
+ public void Fill_InvalidStartIndexCount_ThrowsArgumentOutOfRangeException(int arrayLength, int startIndex, int count)
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => Array.Fill(new string[arrayLength], "", startIndex, count));
+ }
+
+ public static IEnumerable<object[]> Reverse_Generic_Int_TestData()
+ {
+ // TODO: use (or merge this data into) Reverse_TestData if/when xunit/xunit#965 is merged
+ yield return new object[] { new int[] { 1, 2, 3 }, 0, 3, new int[] { 3, 2, 1 } };
+ yield return new object[] { new int[] { 1, 2, 3 }, 0, 2, new int[] { 2, 1, 3 } };
+ yield return new object[] { new int[] { 1, 2, 3 }, 1, 2, new int[] { 1, 3, 2 } };
+
+ // Nothing to reverse
+ yield return new object[] { new int[] { 1, 2, 3 }, 2, 1, new int[] { 1, 2, 3 } };
+ yield return new object[] { new int[] { 1, 2, 3 }, 0, 1, new int[] { 1, 2, 3 } };
+ yield return new object[] { new int[] { 1, 2, 3 }, 0, 0, new int[] { 1, 2, 3 } };
+ yield return new object[] { new int[] { 1, 2, 3 }, 3, 0, new int[] { 1, 2, 3 } };
+ yield return new object[] { new int[0], 0, 0, new int[0] };
+ }
+
+ [Theory]
+ [MemberData(nameof(Reverse_Generic_Int_TestData))]
+ public static void Reverse_Generic(int[] array, int index, int length, int[] expected)
+ {
+ if (index == 0 && length == array.Length)
+ {
+ int[] arrayClone1 = (int[])array.Clone();
+ Array.Reverse(arrayClone1);
+ Assert.Equal(expected, arrayClone1);
+ }
+ int[] arrayClone2 = (int[])array.Clone();
+ Array.Reverse(arrayClone2, index, length);
+ Assert.Equal(expected, arrayClone2);
+ }
+
+ [Fact]
+ public static void Reverse_Generic_NullArray_ThrowsArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Reverse((string[])null));
+ AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Reverse((string[])null, 0, 0));
+ }
+
+ [Fact]
+ public static void Reverse_Generic_NegativeIndex_ThrowsArgumentOutOfRangeException()
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => Array.Reverse(new string[0], -1, 0));
+ }
+
+ [Fact]
+ public static void Reverse_Generic_NegativeLength_ThrowsArgumentOutOfRangeException()
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => Array.Reverse(new string[0], 0, -1));
+ }
+
+ [Theory]
+ [InlineData(0, 0, 1)]
+ [InlineData(3, 4, 0)]
+ [InlineData(3, 3, 1)]
+ [InlineData(3, 2, 2)]
+ [InlineData(3, 1, 3)]
+ [InlineData(3, 0, 4)]
+ public static void Reverse_Generic_InvalidOffsetPlusLength_ThrowsArgumentException(int arrayLength, int index, int length)
+ {
+ AssertExtensions.Throws<ArgumentException>(null, () => Array.Reverse(new string[arrayLength], index, length));
+ }
+
+ [Fact]
+ public static void Reverse_NonSZArrayWithMinValueLowerBound()
+ {
+ Array array = NonZeroLowerBoundArray(new int[] { 1, 2, 3 }, int.MinValue);
+
+ Reverse(array, int.MinValue, 0, new int[] { 1, 2, 3 });
+ Reverse(array, int.MinValue, 1, new int[] { 1, 2, 3 });
+ Reverse(array, int.MinValue, 2, new int[] { 2, 1, 3 });
+ }
+
+ [Fact]
+ public void CreateInstance_TypeNotRuntimeType_ThrowsArgumentException()
+ {
+ // This cannot be a [Theory] due to https://github.com/xunit/xunit/issues/1325.
+ foreach (Type elementType in Helpers.NonRuntimeTypes)
+ {
+ AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, 1));
+ AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, 1, 1));
+ AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, 1, 1, 1));
+ AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, new int[1]));
+ AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, new long[1]));
+ AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, new int[1], new int[1]));
+ }
+ }
+
private static void VerifyArray(Array array, Type elementType, int[] lengths, int[] lowerBounds, object repeatedValue)
{
VerifyArray(array, elementType, lengths, lowerBounds);
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class ArrayTests
- {
- public static IEnumerable<object[]> Fill_Generic_TestData()
- {
- var data = Enumerable.Empty<object[]>();
-
- var r = new Random(0x051778f7);
- int[] lengths = { 0, 1, 2, 3, 5, 8, 13 };
-
- foreach (int length in lengths)
- {
- IEnumerable<int> source = Enumerable.Range(1, length).Select(_ => r.Next());
-
- data = data.Concat(GenerateFillData(source, r.Next(), i => i))
- .Concat(GenerateFillData(source, r.Next(), i => unchecked((byte)i)))
- .Concat(GenerateFillData(source, r.Next(), i => unchecked((short)i)))
- .Concat(GenerateFillData(source, r.Next(), i => (long)i))
- .Concat(GenerateFillData(source, r.Next(), i => new StrongBox<int>(i)))
- .Concat(GenerateFillData(source, r.Next(), i => i.ToString()))
- .Concat(GenerateFillData(source, r.Next(), i => unchecked((ByteEnum)i)))
- .Concat(GenerateFillData(source, r.Next(), i => unchecked((Int16Enum)i)))
- .Concat(GenerateFillData(source, r.Next(), i => (Int32Enum)i))
- .Concat(GenerateFillData(source, r.Next(), i => (Int64Enum)i))
- .Concat(GenerateFillData(source, r.Next(), i => new object()));
- }
-
- return data;
- }
-
- public static IEnumerable<object[]> GenerateFillData<TSource, TResult>(IEnumerable<TSource> source, TSource seed, Func<TSource, TResult> transform)
- {
- int count = source.Count();
- TResult repeatedValue = transform(seed);
- // Force evaluation so neither `source` or `transform` are re-run if the sequence is enumerated more than once.
- IEnumerable<TResult> transformed = source.Select(transform).ToList();
-
- yield return new object[] { transformed, repeatedValue, 0, count }; // Fill the entire array.
- yield return new object[] { transformed, repeatedValue, 0, count / 2 }; // Fill the beginning of the array.
- yield return new object[] { transformed, repeatedValue, count / 2, count / 2 }; // Fill the end of the array, assuming `length` is even.
- yield return new object[] { transformed, repeatedValue, count / 4, count / 2 }; // Fill the middle of the array.
- yield return new object[] { transformed, repeatedValue, count, 0 }; // Fill nothing.
- }
-
- [Theory]
- [MemberData(nameof(Fill_Generic_TestData))]
- public static void Fill_Generic<T>(IEnumerable<T> source, T value, int startIndex, int count)
- {
- if (startIndex == 0 && count == source.Count())
- {
- T[] array = source.ToArray();
- Array.Fill(array, value);
- Assert.Equal(Enumerable.Repeat(value, count), array);
- }
-
- {
- T[] array = source.ToArray();
-
- // Before calling Fill, we want to capture the segments before/after the filled region.
- // We want to ensure that in addition to filling in what it's supposed to, Fill does
- // not touch the adjacent segments.
- T[] before = source.Take(startIndex).ToArray();
- T[] after = source.Skip(startIndex + count).ToArray();
-
- Array.Fill(array, value, startIndex, count);
-
- Assert.Equal(before, array.Take(startIndex));
- Assert.Equal(Enumerable.Repeat(value, count), array.Skip(startIndex).Take(count));
- Assert.Equal(after, array.Skip(startIndex + count));
- }
- }
-
- [Fact]
- public void Fill_NullArray_ThrowsArgumentNullException()
- {
- AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Fill(null, 1));
- AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Fill(null, 1, 0, 0));
- }
-
- [Theory]
- [InlineData(-1)]
- [InlineData(2)]
- public void Fill_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex)
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("startIndex", () => Array.Fill(new string[1], "", startIndex, 0));
- }
-
- [Theory]
- [InlineData(1, 0, -1)]
- [InlineData(0, 0, 1)]
- [InlineData(3, 3, 1)]
- [InlineData(3, 2, 2)]
- [InlineData(3, 1, 3)]
- [InlineData(3, 0, 4)]
- public void Fill_InvalidStartIndexCount_ThrowsArgumentOutOfRangeException(int arrayLength, int startIndex, int count)
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => Array.Fill(new string[arrayLength], "", startIndex, count));
- }
-
- public static IEnumerable<object[]> Reverse_Generic_Int_TestData()
- {
- // TODO: use (or merge this data into) Reverse_TestData if/when xunit/xunit#965 is merged
- yield return new object[] { new int[] { 1, 2, 3 }, 0, 3, new int[] { 3, 2, 1 } };
- yield return new object[] { new int[] { 1, 2, 3 }, 0, 2, new int[] { 2, 1, 3 } };
- yield return new object[] { new int[] { 1, 2, 3 }, 1, 2, new int[] { 1, 3, 2 } };
-
- // Nothing to reverse
- yield return new object[] { new int[] { 1, 2, 3 }, 2, 1, new int[] { 1, 2, 3 } };
- yield return new object[] { new int[] { 1, 2, 3 }, 0, 1, new int[] { 1, 2, 3 } };
- yield return new object[] { new int[] { 1, 2, 3 }, 0, 0, new int[] { 1, 2, 3 } };
- yield return new object[] { new int[] { 1, 2, 3 }, 3, 0, new int[] { 1, 2, 3 } };
- yield return new object[] { new int[0], 0, 0, new int[0] };
- }
-
- [Theory]
- [MemberData(nameof(Reverse_Generic_Int_TestData))]
- public static void Reverse_Generic(int[] array, int index, int length, int[] expected)
- {
- if (index == 0 && length == array.Length)
- {
- int[] arrayClone1 = (int[])array.Clone();
- Array.Reverse(arrayClone1);
- Assert.Equal(expected, arrayClone1);
- }
- int[] arrayClone2 = (int[])array.Clone();
- Array.Reverse(arrayClone2, index, length);
- Assert.Equal(expected, arrayClone2);
- }
-
- [Fact]
- public static void Reverse_Generic_NullArray_ThrowsArgumentNullException()
- {
- AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Reverse((string[])null));
- AssertExtensions.Throws<ArgumentNullException>("array", () => Array.Reverse((string[])null, 0, 0));
- }
-
- [Fact]
- public static void Reverse_Generic_NegativeIndex_ThrowsArgumentOutOfRangeException()
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => Array.Reverse(new string[0], -1, 0));
- }
-
- [Fact]
- public static void Reverse_Generic_NegativeLength_ThrowsArgumentOutOfRangeException()
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => Array.Reverse(new string[0], 0, -1));
- }
-
- [Theory]
- [InlineData(0, 0, 1)]
- [InlineData(3, 4, 0)]
- [InlineData(3, 3, 1)]
- [InlineData(3, 2, 2)]
- [InlineData(3, 1, 3)]
- [InlineData(3, 0, 4)]
- public static void Reverse_Generic_InvalidOffsetPlusLength_ThrowsArgumentException(int arrayLength, int index, int length)
- {
- AssertExtensions.Throws<ArgumentException>(null, () => Array.Reverse(new string[arrayLength], index, length));
- }
-
- [Fact]
- public static void Reverse_NonSZArrayWithMinValueLowerBound()
- {
- Array array = NonZeroLowerBoundArray(new int[] { 1, 2, 3 }, int.MinValue);
-
- Reverse(array, int.MinValue, 0, new int[] { 1, 2, 3 });
- Reverse(array, int.MinValue, 1, new int[] { 1, 2, 3 });
- Reverse(array, int.MinValue, 2, new int[] { 2, 1, 3 });
- }
-
- [Fact]
- public void CreateInstance_TypeNotRuntimeType_ThrowsArgumentException()
- {
- // This cannot be a [Theory] due to https://github.com/xunit/xunit/issues/1325.
- foreach (Type elementType in Helpers.NonRuntimeTypes)
- {
- AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, 1));
- AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, 1, 1));
- AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, 1, 1, 1));
- AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, new int[1]));
- AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, new long[1]));
- AssertExtensions.Throws<ArgumentException>("elementType", () => Array.CreateInstance(elementType, new int[1], new int[1]));
- }
- }
- }
-}
{
Assert.Equal(TypeCode.Boolean, true.GetTypeCode());
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1] };
+ }
+
+ yield return new object[] { " \0 \0 TrueFalse \0 ", 6, 4, true };
+ yield return new object[] { " \0 \0 TrueFalse \0 ", 10, 5, false };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, bool expected)
+ {
+ Assert.Equal(expected, bool.Parse(value.AsSpan(offset, count)));
+
+ Assert.True(bool.TryParse(value.AsSpan(offset, count), out bool result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, Type exceptionType)
+ {
+ if (value != null)
+ {
+ Assert.Throws(exceptionType, () => bool.Parse(value.AsSpan()));
+
+ Assert.False(bool.TryParse(value.AsSpan(), out bool result));
+ Assert.False(result);
+ }
+ }
+
+ [Theory]
+ [InlineData(true, "True")]
+ [InlineData(false, "False")]
+ public static void TryFormat(bool i, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten));
+ Assert.Equal(0, charsWritten);
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class BooleanTests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1] };
- }
-
- yield return new object[] { " \0 \0 TrueFalse \0 ", 6, 4, true };
- yield return new object[] { " \0 \0 TrueFalse \0 ", 10, 5, false };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, bool expected)
- {
- Assert.Equal(expected, bool.Parse(value.AsSpan(offset, count)));
-
- Assert.True(bool.TryParse(value.AsSpan(offset, count), out bool result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, Type exceptionType)
- {
- if (value != null)
- {
- Assert.Throws(exceptionType, () => bool.Parse(value.AsSpan()));
-
- Assert.False(bool.TryParse(value.AsSpan(), out bool result));
- Assert.False(result);
- }
- }
-
- [Theory]
- [InlineData(true, "True")]
- [InlineData(false, "False")]
- public static void TryFormat(bool i, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten));
- Assert.Equal(0, charsWritten);
- }
- }
- }
-}
namespace System.Tests
{
- public partial class ByteTests
+ public class ByteTests
{
[Fact]
public static void Ctor_Empty()
AssertExtensions.Throws<ArgumentException>(paramName, () => byte.Parse("1", style));
AssertExtensions.Throws<ArgumentException>(paramName, () => byte.Parse("1", style, null));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (byte)12 };
+ yield return new object[] { "+123", 0, 2, NumberStyles.Integer, null, (byte)1 };
+ yield return new object[] { "+123", 1, 3, NumberStyles.Integer, null, (byte)123 };
+ yield return new object[] { " 123 ", 4, 1, NumberStyles.Integer, null, (byte)3 };
+ yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (byte)0x2 };
+ yield return new object[] { "10", 0, 1, NumberStyles.AllowThousands, null, (byte)1 };
+ yield return new object[] { "$100", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (byte)1 };
+ }
+
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, byte expected)
+ {
+ byte result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(byte.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, byte.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(byte.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ byte result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(byte.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0u, result);
+ }
+
+ Assert.Throws(exceptionType, () => byte.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(byte.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0u, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(byte i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class ByteTests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (byte)12 };
- yield return new object[] { "+123", 0, 2, NumberStyles.Integer, null, (byte)1 };
- yield return new object[] { "+123", 1, 3, NumberStyles.Integer, null, (byte)123 };
- yield return new object[] { " 123 ", 4, 1, NumberStyles.Integer, null, (byte)3 };
- yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (byte)0x2 };
- yield return new object[] { "10", 0, 1, NumberStyles.AllowThousands, null, (byte)1 };
- yield return new object[] { "$100", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (byte)1 };
- }
-
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, byte expected)
- {
- byte result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(byte.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, byte.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(byte.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- byte result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(byte.TryParse(value.AsSpan(), out result));
- Assert.Equal(0u, result);
- }
-
- Assert.Throws(exceptionType, () => byte.Parse(value.AsSpan(), style, provider));
-
- Assert.False(byte.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0u, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(byte i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
using System.Collections.Generic;
using System.Globalization;
using System.Text;
+using System.Text.Unicode.Tests;
using Xunit;
+using Xunit.Sdk;
namespace System.Tests
{
- public partial class CharTests
+ public class CharTests
{
[Theory]
[InlineData('h', 'h', 0)]
Assert.Equal(lowerForm, char.ToLower(upperForm, ci));
Assert.Equal(upperForm, char.ToUpper(lowerForm, ci));
}
+
+ [OuterLoop]
+ [Fact]
+ public static void GetUnicodeCategory_Char_AllInputs()
+ {
+ // This tests calls char.GetUnicodeCategory for every possible input, ensuring that
+ // the runtime agrees with the data in the core Unicode files.
+
+ for (uint i = 0; i <= char.MaxValue; i++)
+ {
+ UnicodeCategory expected;
+
+ // The code points in the switch block below must be special-cased
+ // because they switched categories between versions of the Unicode
+ // specification. For compatibility reasons Char keeps its own copy
+ // of the categories for the first 256 code points, as it's locked
+ // to an earlier version of the standard. For an example of a code
+ // point that switched categories, see the discussion on U+00AD
+ // SOFT HYPHEN at https://www.unicode.org/versions/Unicode4.0.0/.
+
+ switch (i)
+ {
+ case '\u00a7':
+ case '\u00b6':
+ expected = UnicodeCategory.OtherSymbol;
+ break;
+
+ case '\u00aa':
+ case '\u00ba':
+ expected = UnicodeCategory.LowercaseLetter;
+ break;
+
+ case '\u00ad':
+ expected = UnicodeCategory.DashPunctuation;
+ break;
+
+ default:
+ expected = UnicodeData.GetUnicodeCategory(i);
+ break;
+ }
+
+ if (expected != char.GetUnicodeCategory((char)i))
+ {
+ // We'll build up the exception message ourselves so the dev knows what code point failed.
+ throw new AssertActualExpectedException(
+ expected: expected,
+ actual: char.GetUnicodeCategory((char)i),
+ userMessage: FormattableString.Invariant($@"char.GetUnicodeCategory('\u{i:X4}') returned wrong value."));
+ }
+ }
+ }
+
+ [OuterLoop]
+ [Fact]
+ public static void IsLetter_Char_AllInputs()
+ {
+ // This tests calls char.IsLetter for every possible input, ensuring that
+ // the runtime agrees with the data in the core Unicode files.
+
+ for (uint i = 0; i <= char.MaxValue; i++)
+ {
+ if (UnicodeData.IsLetter((char)i) != char.IsLetter((char)i))
+ {
+ // We'll build up the exception message ourselves so the dev knows what code point failed.
+ throw new AssertActualExpectedException(
+ expected: UnicodeData.IsLetter((char)i),
+ actual: char.IsLetter((char)i),
+ userMessage: FormattableString.Invariant($@"char.IsLetter('\u{i:X4}') returned wrong value."));
+ }
+ }
+ }
+
+ [OuterLoop]
+ [Fact]
+ public static void IsLower_Char_AllInputs()
+ {
+ // This tests calls char.IsLower for every possible input, ensuring that
+ // the runtime agrees with the data in the core Unicode files.
+
+ for (uint i = 0; i <= char.MaxValue; i++)
+ {
+ bool expected;
+
+ switch (i)
+ {
+ case '\u00AA': // FEMININE ORDINAL INDICATOR
+ case '\u00BA': // MASCULINE ORDINAL INDICATOR
+
+ // In Unicode 6.1 the code points U+00AA and U+00BA were reassigned
+ // from category Ll to category Lo. However, for compatibility reasons,
+ // Char uses the older version of the Unicode standard for code points
+ // in the range U+0000..U+00FF. So we'll special-case these here.
+ // More info: https://www.unicode.org/review/pri181/
+
+ expected = true;
+ break;
+
+ default:
+ expected = UnicodeData.GetUnicodeCategory((char)i) == UnicodeCategory.LowercaseLetter;
+ break;
+ }
+
+ if (expected != char.IsLower((char)i))
+ {
+ // We'll build up the exception message ourselves so the dev knows what code point failed.
+ throw new AssertActualExpectedException(
+ expected: expected,
+ actual: char.IsLower((char)i),
+ userMessage: FormattableString.Invariant($@"char.IsLower('\u{i:X4}') returned wrong value."));
+ }
+ }
+ }
+
+ [OuterLoop]
+ [Fact]
+ public static void IsUpper_Char_AllInputs()
+ {
+ // This tests calls char.IsUpper for every possible input, ensuring that
+ // the runtime agrees with the data in the core Unicode files.
+
+ for (uint i = 0; i <= char.MaxValue; i++)
+ {
+ bool expected = UnicodeData.GetUnicodeCategory((char)i) == UnicodeCategory.UppercaseLetter;
+
+ if (expected != char.IsUpper((char)i))
+ {
+ // We'll build up the exception message ourselves so the dev knows what code point failed.
+ throw new AssertActualExpectedException(
+ expected: expected,
+ actual: char.IsUpper((char)i),
+ userMessage: FormattableString.Invariant($@"char.IsUpper('\u{i:X4}') returned wrong value."));
+ }
+ }
+ }
+
+ [OuterLoop]
+ [Fact]
+ public static void IsWhiteSpace_Char_AllInputs()
+ {
+ // This tests calls char.IsWhiteSpace for every possible input, ensuring that
+ // the runtime agrees with the data in the core Unicode files.
+
+ for (uint i = 0; i <= char.MaxValue; i++)
+ {
+ if (UnicodeData.IsWhiteSpace(i) != char.IsWhiteSpace((char)i))
+ {
+ // We'll build up the exception message ourselves so the dev knows what code point failed.
+ throw new AssertActualExpectedException(
+ expected: UnicodeData.IsWhiteSpace(i),
+ actual: char.IsWhiteSpace((char)i),
+ userMessage: FormattableString.Invariant($@"char.IsWhiteSpace('\u{i:X4}') returned wrong value."));
+ }
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Globalization;
-using System.Text.Unicode.Tests;
-using Xunit;
-using Xunit.Sdk;
-
-namespace System.Tests
-{
- public partial class CharTests
- {
- [OuterLoop]
- [Fact]
- public static void GetUnicodeCategory_Char_AllInputs()
- {
- // This tests calls char.GetUnicodeCategory for every possible input, ensuring that
- // the runtime agrees with the data in the core Unicode files.
-
- for (uint i = 0; i <= char.MaxValue; i++)
- {
- UnicodeCategory expected;
-
- // The code points in the switch block below must be special-cased
- // because they switched categories between versions of the Unicode
- // specification. For compatibility reasons Char keeps its own copy
- // of the categories for the first 256 code points, as it's locked
- // to an earlier version of the standard. For an example of a code
- // point that switched categories, see the discussion on U+00AD
- // SOFT HYPHEN at https://www.unicode.org/versions/Unicode4.0.0/.
-
- switch (i)
- {
- case '\u00a7':
- case '\u00b6':
- expected = UnicodeCategory.OtherSymbol;
- break;
-
- case '\u00aa':
- case '\u00ba':
- expected = UnicodeCategory.LowercaseLetter;
- break;
-
- case '\u00ad':
- expected = UnicodeCategory.DashPunctuation;
- break;
-
- default:
- expected = UnicodeData.GetUnicodeCategory(i);
- break;
- }
-
- if (expected != char.GetUnicodeCategory((char)i))
- {
- // We'll build up the exception message ourselves so the dev knows what code point failed.
- throw new AssertActualExpectedException(
- expected: expected,
- actual: char.GetUnicodeCategory((char)i),
- userMessage: FormattableString.Invariant($@"char.GetUnicodeCategory('\u{i:X4}') returned wrong value."));
- }
- }
- }
-
- [OuterLoop]
- [Fact]
- public static void IsLetter_Char_AllInputs()
- {
- // This tests calls char.IsLetter for every possible input, ensuring that
- // the runtime agrees with the data in the core Unicode files.
-
- for (uint i = 0; i <= char.MaxValue; i++)
- {
- if (UnicodeData.IsLetter((char)i) != char.IsLetter((char)i))
- {
- // We'll build up the exception message ourselves so the dev knows what code point failed.
- throw new AssertActualExpectedException(
- expected: UnicodeData.IsLetter((char)i),
- actual: char.IsLetter((char)i),
- userMessage: FormattableString.Invariant($@"char.IsLetter('\u{i:X4}') returned wrong value."));
- }
- }
- }
-
- [OuterLoop]
- [Fact]
- public static void IsLower_Char_AllInputs()
- {
- // This tests calls char.IsLower for every possible input, ensuring that
- // the runtime agrees with the data in the core Unicode files.
-
- for (uint i = 0; i <= char.MaxValue; i++)
- {
- bool expected;
-
- switch (i)
- {
- case '\u00AA': // FEMININE ORDINAL INDICATOR
- case '\u00BA': // MASCULINE ORDINAL INDICATOR
-
- // In Unicode 6.1 the code points U+00AA and U+00BA were reassigned
- // from category Ll to category Lo. However, for compatibility reasons,
- // Char uses the older version of the Unicode standard for code points
- // in the range U+0000..U+00FF. So we'll special-case these here.
- // More info: https://www.unicode.org/review/pri181/
-
- expected = true;
- break;
-
- default:
- expected = UnicodeData.GetUnicodeCategory((char)i) == UnicodeCategory.LowercaseLetter;
- break;
- }
-
- if (expected != char.IsLower((char)i))
- {
- // We'll build up the exception message ourselves so the dev knows what code point failed.
- throw new AssertActualExpectedException(
- expected: expected,
- actual: char.IsLower((char)i),
- userMessage: FormattableString.Invariant($@"char.IsLower('\u{i:X4}') returned wrong value."));
- }
- }
- }
-
- [OuterLoop]
- [Fact]
- public static void IsUpper_Char_AllInputs()
- {
- // This tests calls char.IsUpper for every possible input, ensuring that
- // the runtime agrees with the data in the core Unicode files.
-
- for (uint i = 0; i <= char.MaxValue; i++)
- {
- bool expected = UnicodeData.GetUnicodeCategory((char)i) == UnicodeCategory.UppercaseLetter;
-
- if (expected != char.IsUpper((char)i))
- {
- // We'll build up the exception message ourselves so the dev knows what code point failed.
- throw new AssertActualExpectedException(
- expected: expected,
- actual: char.IsUpper((char)i),
- userMessage: FormattableString.Invariant($@"char.IsUpper('\u{i:X4}') returned wrong value."));
- }
- }
- }
-
- [OuterLoop]
- [Fact]
- public static void IsWhiteSpace_Char_AllInputs()
- {
- // This tests calls char.IsWhiteSpace for every possible input, ensuring that
- // the runtime agrees with the data in the core Unicode files.
-
- for (uint i = 0; i <= char.MaxValue; i++)
- {
- if (UnicodeData.IsWhiteSpace(i) != char.IsWhiteSpace((char)i))
- {
- // We'll build up the exception message ourselves so the dev knows what code point failed.
- throw new AssertActualExpectedException(
- expected: UnicodeData.IsWhiteSpace(i),
- actual: char.IsWhiteSpace((char)i),
- userMessage: FormattableString.Invariant($@"char.IsWhiteSpace('\u{i:X4}') returned wrong value."));
- }
- }
- }
- }
-}
namespace System.Collections.Generic.Tests
{
- public partial class KeyValuePairTests
+ public class KeyValuePairTests
{
[Fact]
public void Ctor_KeyValue_ReturnsExpected()
var keyValuePair = new KeyValuePair<string, string>(null, null);
Assert.Equal("[, ]", keyValuePair.ToString());
}
+
+ [Fact]
+ public void Create_ReturnsExpected()
+ {
+ KeyValuePair<int, string> keyValuePair = KeyValuePair.Create(1, "2");
+ Assert.Equal(1, keyValuePair.Key);
+ Assert.Equal("2", keyValuePair.Value);
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Xunit;
-
-namespace System.Collections.Generic.Tests
-{
- public partial class KeyValuePairTests
- {
- [Fact]
- public void Create_ReturnsExpected()
- {
- KeyValuePair<int, string> keyValuePair = KeyValuePair.Create(1, "2");
- Assert.Equal(1, keyValuePair.Key);
- Assert.Equal("2", keyValuePair.Value);
- }
- }
-}
namespace System.ComponentModel.Tests
{
- public partial class DefaultValueAttributeTests
+ public class DefaultValueAttributeTests
{
[Fact]
public static void Ctor()
Assert.Equal(3.14f, new DefaultValueAttribute(3.14f).Value);
Assert.Equal((byte)1, new DefaultValueAttribute((byte)1).Value);
+ Assert.Equal((sbyte)42, new DefaultValueAttribute((sbyte)42).Value);
+
Assert.Equal(42, new DefaultValueAttribute(42).Value);
+ Assert.Equal((uint)42, new DefaultValueAttribute((uint)42).Value);
+
Assert.Equal(42L, new DefaultValueAttribute(42L).Value);
+ Assert.Equal((ulong)42, new DefaultValueAttribute((ulong)42).Value);
+
Assert.Equal((short)42, new DefaultValueAttribute((short)42).Value);
+ Assert.Equal((ushort)42, new DefaultValueAttribute((ushort)42).Value);
Assert.Equal('c', new DefaultValueAttribute('c').Value);
Assert.Equal("test", new DefaultValueAttribute("test").Value);
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using Xunit;
-
-namespace System.ComponentModel.Tests
-{
- public partial class DefaultValueAttributeTests
- {
- [Fact]
- public static void Ctor_netcoreapp11()
- {
- Assert.Equal((sbyte)42, new DefaultValueAttribute((sbyte)42).Value);
- Assert.Equal((ushort)42, new DefaultValueAttribute((ushort)42).Value);
- Assert.Equal((uint)42, new DefaultValueAttribute((uint)42).Value);
- Assert.Equal((ulong)42, new DefaultValueAttribute((ulong)42).Value);
- }
- }
-}
namespace System.Tests
{
- public static partial class DateTimeOffsetTests
+ public static class DateTimeOffsetTests
{
[Fact]
public static void MaxValue()
{
Assert.Equal(expected, dateTimeOffset.ToString(format, culture));
}
+
+ [Fact]
+ public static void ToString_ParseSpan_RoundtripsSuccessfully()
+ {
+ DateTimeOffset expected = DateTimeOffset.MaxValue;
+ string expectedString = expected.ToString();
+
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan()).ToString());
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan(), null).ToString());
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan(), null, DateTimeStyles.None).ToString());
+
+ Assert.True(DateTimeOffset.TryParse(expectedString.AsSpan(), out DateTimeOffset actual));
+ Assert.Equal(expectedString, actual.ToString());
+ Assert.True(DateTimeOffset.TryParse(expectedString.AsSpan(), null, DateTimeStyles.None, out actual));
+ Assert.Equal(expectedString, actual.ToString());
+ }
+
+ [Theory]
+ [InlineData("r")]
+ [InlineData("o")]
+ public static void ToString_Slice_ParseSpan_RoundtripsSuccessfully(string roundtripFormat)
+ {
+ string expectedString = DateTimeOffset.UtcNow.ToString(roundtripFormat);
+ ReadOnlySpan<char> expectedSpan = ("abcd" + expectedString + "1234").AsSpan("abcd".Length, expectedString.Length);
+
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedSpan).ToString(roundtripFormat));
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedSpan, null).ToString(roundtripFormat));
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedSpan, null, DateTimeStyles.None).ToString(roundtripFormat));
+
+ Assert.True(DateTimeOffset.TryParse(expectedSpan, out DateTimeOffset actual));
+ Assert.Equal(expectedString, actual.ToString(roundtripFormat));
+ Assert.True(DateTimeOffset.TryParse(expectedSpan, null, DateTimeStyles.None, out actual));
+ Assert.Equal(expectedString, actual.ToString(roundtripFormat));
+ }
+
+ [Fact]
+ public static void ToString_ParseExactSpan_RoundtripsSuccessfully()
+ {
+ DateTimeOffset expected = DateTimeOffset.MaxValue;
+ string expectedString = expected.ToString("u");
+
+ Assert.Equal(expectedString, DateTimeOffset.ParseExact(expectedString, "u", null, DateTimeStyles.None).ToString("u"));
+ Assert.Equal(expectedString, DateTimeOffset.ParseExact(expectedString, new[] { "u" }, null, DateTimeStyles.None).ToString("u"));
+
+ Assert.True(DateTimeOffset.TryParseExact(expectedString, "u", null, DateTimeStyles.None, out DateTimeOffset actual));
+ Assert.Equal(expectedString, actual.ToString("u"));
+ Assert.True(DateTimeOffset.TryParseExact(expectedString, new[] { "u" }, null, DateTimeStyles.None, out actual));
+ Assert.Equal(expectedString, actual.ToString("u"));
+ }
+
+ [Fact]
+ public static void TryFormat_ToString_EqualResults()
+ {
+ DateTimeOffset expected = DateTimeOffset.MaxValue;
+ string expectedString = expected.ToString();
+
+ // Just the right amount of space, succeeds
+ Span<char> actual = new char[expectedString.Length];
+ Assert.True(expected.TryFormat(actual, out int charsWritten));
+ Assert.Equal(expectedString.Length, charsWritten);
+ Assert.Equal<char>(expectedString.ToCharArray(), actual.ToArray());
+
+ // Too little space, fails
+ actual = new char[expectedString.Length - 1];
+ Assert.False(expected.TryFormat(actual, out charsWritten));
+ Assert.Equal(0, charsWritten);
+
+ // More than enough space, succeeds
+ actual = new char[expectedString.Length + 1];
+ Assert.True(expected.TryFormat(actual, out charsWritten));
+ Assert.Equal(expectedString.Length, charsWritten);
+ Assert.Equal<char>(expectedString.ToCharArray(), actual.Slice(0, expectedString.Length).ToArray());
+ Assert.Equal(0, actual[actual.Length - 1]);
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_MatchesExpected_MemberData))]
+ public static void TryFormat_MatchesExpected(DateTimeOffset dateTimeOffset, string format, IFormatProvider provider, string expected)
+ {
+ var destination = new char[expected.Length];
+
+ Assert.False(dateTimeOffset.TryFormat(destination.AsSpan(0, destination.Length - 1), out _, format, provider));
+
+ Assert.True(dateTimeOffset.TryFormat(destination, out int charsWritten, format, provider));
+ Assert.Equal(destination.Length, charsWritten);
+ Assert.Equal(expected, new string(destination));
+ }
+
+ [Fact]
+ public static void UnixEpoch()
+ {
+ VerifyDateTimeOffset(DateTimeOffset.UnixEpoch, 1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public static partial class DateTimeOffsetTests
- {
- [Fact]
- public static void ToString_ParseSpan_RoundtripsSuccessfully()
- {
- DateTimeOffset expected = DateTimeOffset.MaxValue;
- string expectedString = expected.ToString();
-
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan()).ToString());
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan(), null).ToString());
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan(), null, DateTimeStyles.None).ToString());
-
- Assert.True(DateTimeOffset.TryParse(expectedString.AsSpan(), out DateTimeOffset actual));
- Assert.Equal(expectedString, actual.ToString());
- Assert.True(DateTimeOffset.TryParse(expectedString.AsSpan(), null, DateTimeStyles.None, out actual));
- Assert.Equal(expectedString, actual.ToString());
- }
-
- [Theory]
- [InlineData("r")]
- [InlineData("o")]
- public static void ToString_Slice_ParseSpan_RoundtripsSuccessfully(string roundtripFormat)
- {
- string expectedString = DateTimeOffset.UtcNow.ToString(roundtripFormat);
- ReadOnlySpan<char> expectedSpan = ("abcd" + expectedString + "1234").AsSpan("abcd".Length, expectedString.Length);
-
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedSpan).ToString(roundtripFormat));
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedSpan, null).ToString(roundtripFormat));
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedSpan, null, DateTimeStyles.None).ToString(roundtripFormat));
-
- Assert.True(DateTimeOffset.TryParse(expectedSpan, out DateTimeOffset actual));
- Assert.Equal(expectedString, actual.ToString(roundtripFormat));
- Assert.True(DateTimeOffset.TryParse(expectedSpan, null, DateTimeStyles.None, out actual));
- Assert.Equal(expectedString, actual.ToString(roundtripFormat));
- }
-
- [Fact]
- public static void ToString_ParseExactSpan_RoundtripsSuccessfully()
- {
- DateTimeOffset expected = DateTimeOffset.MaxValue;
- string expectedString = expected.ToString("u");
-
- Assert.Equal(expectedString, DateTimeOffset.ParseExact(expectedString, "u", null, DateTimeStyles.None).ToString("u"));
- Assert.Equal(expectedString, DateTimeOffset.ParseExact(expectedString, new[] { "u" }, null, DateTimeStyles.None).ToString("u"));
-
- Assert.True(DateTimeOffset.TryParseExact(expectedString, "u", null, DateTimeStyles.None, out DateTimeOffset actual));
- Assert.Equal(expectedString, actual.ToString("u"));
- Assert.True(DateTimeOffset.TryParseExact(expectedString, new[] { "u" }, null, DateTimeStyles.None, out actual));
- Assert.Equal(expectedString, actual.ToString("u"));
- }
-
- [Fact]
- public static void TryFormat_ToString_EqualResults()
- {
- DateTimeOffset expected = DateTimeOffset.MaxValue;
- string expectedString = expected.ToString();
-
- // Just the right amount of space, succeeds
- Span<char> actual = new char[expectedString.Length];
- Assert.True(expected.TryFormat(actual, out int charsWritten));
- Assert.Equal(expectedString.Length, charsWritten);
- Assert.Equal<char>(expectedString.ToCharArray(), actual.ToArray());
-
- // Too little space, fails
- actual = new char[expectedString.Length - 1];
- Assert.False(expected.TryFormat(actual, out charsWritten));
- Assert.Equal(0, charsWritten);
-
- // More than enough space, succeeds
- actual = new char[expectedString.Length + 1];
- Assert.True(expected.TryFormat(actual, out charsWritten));
- Assert.Equal(expectedString.Length, charsWritten);
- Assert.Equal<char>(expectedString.ToCharArray(), actual.Slice(0, expectedString.Length).ToArray());
- Assert.Equal(0, actual[actual.Length - 1]);
- }
-
- [Theory]
- [MemberData(nameof(ToString_MatchesExpected_MemberData))]
- public static void TryFormat_MatchesExpected(DateTimeOffset dateTimeOffset, string format, IFormatProvider provider, string expected)
- {
- var destination = new char[expected.Length];
-
- Assert.False(dateTimeOffset.TryFormat(destination.AsSpan(0, destination.Length - 1), out _, format, provider));
-
- Assert.True(dateTimeOffset.TryFormat(destination, out int charsWritten, format, provider));
- Assert.Equal(destination.Length, charsWritten);
- Assert.Equal(expected, new string(destination));
- }
-
- [Fact]
- public static void UnixEpoch()
- {
- VerifyDateTimeOffset(DateTimeOffset.UnixEpoch, 1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
- }
- }
-}
namespace System.Tests
{
- public partial class DateTimeTests
+ public class DateTimeTests
{
[Fact]
public static void MaxValue()
return DateTime.MaxValue;
}
}
+
+ [Theory]
+ [MemberData(nameof(StandardFormatSpecifiers))]
+ public static void TryFormat_MatchesToString(string format)
+ {
+ DateTime dt = DateTime.UtcNow;
+ string expected = dt.ToString(format);
+
+ // Just the right length, succeeds
+ Span<char> dest = new char[expected.Length];
+ Assert.True(dt.TryFormat(dest, out int charsWritten, format));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal<char>(expected.ToCharArray(), dest.ToArray());
+
+ // Too short, fails
+ dest = new char[expected.Length - 1];
+ Assert.False(dt.TryFormat(dest, out charsWritten, format));
+ Assert.Equal(0, charsWritten);
+
+ // Longer than needed, succeeds
+ dest = new char[expected.Length + 1];
+ Assert.True(dt.TryFormat(dest, out charsWritten, format));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal<char>(expected.ToCharArray(), dest.Slice(0, expected.Length).ToArray());
+ Assert.Equal(0, dest[dest.Length - 1]);
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_MatchesExpected_MemberData))]
+ public static void TryFormat_MatchesExpected(DateTime dateTime, string format, IFormatProvider provider, string expected)
+ {
+ var destination = new char[expected.Length];
+
+ Assert.False(dateTime.TryFormat(destination.AsSpan(0, destination.Length - 1), out _, format, provider));
+
+ Assert.True(dateTime.TryFormat(destination, out int charsWritten, format, provider));
+ Assert.Equal(destination.Length, charsWritten);
+ Assert.Equal(expected, new string(destination));
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidInput_Succeeds_MemberData))]
+ public static void Parse_Span_ValidInput_Succeeds(string input, CultureInfo culture, DateTime? expected)
+ {
+ Assert.Equal(expected, DateTime.Parse(input.AsSpan(), culture));
+ }
+
+ [Theory]
+ [MemberData(nameof(ParseExact_ValidInput_Succeeds_MemberData))]
+ public static void ParseExact_Span_ValidInput_Succeeds(string input, string format, CultureInfo culture, DateTimeStyles style, DateTime? expected)
+ {
+ DateTime result1 = DateTime.ParseExact(input.AsSpan(), format, culture, style);
+ DateTime result2 = DateTime.ParseExact(input.AsSpan(), new[] { format }, culture, style);
+
+ Assert.True(DateTime.TryParseExact(input.AsSpan(), format, culture, style, out DateTime result3));
+ Assert.True(DateTime.TryParseExact(input.AsSpan(), new[] { format }, culture, style, out DateTime result4));
+
+ Assert.Equal(result1, result2);
+ Assert.Equal(result1, result3);
+ Assert.Equal(result1, result4);
+
+ if (expected != null) // some inputs don't roundtrip well
+ {
+ // Normalize values to make comparison easier
+ if (expected.Value.Kind != DateTimeKind.Utc)
+ {
+ expected = expected.Value.ToUniversalTime();
+ }
+ if (result1.Kind != DateTimeKind.Utc)
+ {
+ result1 = result1.ToUniversalTime();
+ }
+
+ Assert.Equal(expected, result1);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ParseExact_InvalidInputs_Fail_MemberData))]
+ public static void ParseExact_Span_InvalidInputs_Fail(string input, string format, CultureInfo culture, DateTimeStyles style)
+ {
+ Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsSpan(), format, culture, style));
+ Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsSpan(), new[] { format }, culture, style));
+
+ Assert.False(DateTime.TryParseExact(input.AsSpan(), format, culture, style, out DateTime result));
+ Assert.False(DateTime.TryParseExact(input.AsSpan(), new[] { format }, culture, style, out result));
+ }
+
+ [Fact]
+ public static void UnixEpoch()
+ {
+ VerifyDateTime(DateTime.UnixEpoch, 1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class DateTimeTests
- {
- [Theory]
- [MemberData(nameof(StandardFormatSpecifiers))]
- public static void TryFormat_MatchesToString(string format)
- {
- DateTime dt = DateTime.UtcNow;
- string expected = dt.ToString(format);
-
- // Just the right length, succeeds
- Span<char> dest = new char[expected.Length];
- Assert.True(dt.TryFormat(dest, out int charsWritten, format));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal<char>(expected.ToCharArray(), dest.ToArray());
-
- // Too short, fails
- dest = new char[expected.Length - 1];
- Assert.False(dt.TryFormat(dest, out charsWritten, format));
- Assert.Equal(0, charsWritten);
-
- // Longer than needed, succeeds
- dest = new char[expected.Length + 1];
- Assert.True(dt.TryFormat(dest, out charsWritten, format));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal<char>(expected.ToCharArray(), dest.Slice(0, expected.Length).ToArray());
- Assert.Equal(0, dest[dest.Length - 1]);
- }
-
- [Theory]
- [MemberData(nameof(ToString_MatchesExpected_MemberData))]
- public static void TryFormat_MatchesExpected(DateTime dateTime, string format, IFormatProvider provider, string expected)
- {
- var destination = new char[expected.Length];
-
- Assert.False(dateTime.TryFormat(destination.AsSpan(0, destination.Length - 1), out _, format, provider));
-
- Assert.True(dateTime.TryFormat(destination, out int charsWritten, format, provider));
- Assert.Equal(destination.Length, charsWritten);
- Assert.Equal(expected, new string(destination));
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidInput_Succeeds_MemberData))]
- public static void Parse_Span_ValidInput_Succeeds(string input, CultureInfo culture, DateTime? expected)
- {
- Assert.Equal(expected, DateTime.Parse(input.AsSpan(), culture));
- }
-
- [Theory]
- [MemberData(nameof(ParseExact_ValidInput_Succeeds_MemberData))]
- public static void ParseExact_Span_ValidInput_Succeeds(string input, string format, CultureInfo culture, DateTimeStyles style, DateTime? expected)
- {
- DateTime result1 = DateTime.ParseExact(input.AsSpan(), format, culture, style);
- DateTime result2 = DateTime.ParseExact(input.AsSpan(), new[] { format }, culture, style);
-
- Assert.True(DateTime.TryParseExact(input.AsSpan(), format, culture, style, out DateTime result3));
- Assert.True(DateTime.TryParseExact(input.AsSpan(), new[] { format }, culture, style, out DateTime result4));
-
- Assert.Equal(result1, result2);
- Assert.Equal(result1, result3);
- Assert.Equal(result1, result4);
-
- if (expected != null) // some inputs don't roundtrip well
- {
- // Normalize values to make comparison easier
- if (expected.Value.Kind != DateTimeKind.Utc)
- {
- expected = expected.Value.ToUniversalTime();
- }
- if (result1.Kind != DateTimeKind.Utc)
- {
- result1 = result1.ToUniversalTime();
- }
-
- Assert.Equal(expected, result1);
- }
- }
-
- [Theory]
- [MemberData(nameof(ParseExact_InvalidInputs_Fail_MemberData))]
- public static void ParseExact_Span_InvalidInputs_Fail(string input, string format, CultureInfo culture, DateTimeStyles style)
- {
- Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsSpan(), format, culture, style));
- Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsSpan(), new[] { format }, culture, style));
-
- Assert.False(DateTime.TryParseExact(input.AsSpan(), format, culture, style, out DateTime result));
- Assert.False(DateTime.TryParseExact(input.AsSpan(), new[] { format }, culture, style, out result));
- }
-
- [Fact]
- public static void UnixEpoch()
- {
- VerifyDateTime(DateTime.UnixEpoch, 1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
- }
- }
-}
namespace System.Tests
{
- public partial class DecimalTests
+ public class DecimalTests
{
[Fact]
public void MaxValue_Get_ReturnsExpected()
return new BigDecimal(res, (byte)scale);
}
}
+
+ [Theory]
+ [InlineData(MidpointRounding.ToEven - 1)]
+ [InlineData(MidpointRounding.ToPositiveInfinity + 1)]
+ public void Round_InvalidMidpointRounding_ThrowsArgumentException(MidpointRounding mode)
+ {
+ AssertExtensions.Throws<ArgumentException>("mode", () => decimal.Round(1, 2, mode));
+ }
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "-123", 1, 3, NumberStyles.Number, null, 123m };
+ yield return new object[] { "-123", 0, 3, NumberStyles.Number, null, -12m };
+ yield return new object[] { 1000.ToString("N0"), 0, 4, NumberStyles.AllowThousands, null, 100m };
+ yield return new object[] { 1000.ToString("N0"), 2, 3, NumberStyles.AllowThousands, null, 0m };
+ yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, 123m };
+ yield return new object[] { "1234567890123456789012345.678456", 1, 4, NumberStyles.Number, new NumberFormatInfo() { NumberDecimalSeparator = "." }, 2345m };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, decimal expected)
+ {
+ bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
+ decimal result;
+ if ((style & ~NumberStyles.Number) == 0 && style != NumberStyles.None)
+ {
+ // Use Parse(string) or Parse(string, IFormatProvider)
+ if (isDefaultProvider)
+ {
+ Assert.True(decimal.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+
+ Assert.Equal(expected, decimal.Parse(value.AsSpan(offset, count)));
+ }
+
+ Assert.Equal(expected, decimal.Parse(value.AsSpan(offset, count), provider: provider));
+ }
+
+ Assert.Equal(expected, decimal.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(decimal.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ Assert.Throws(exceptionType, () => decimal.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(decimal.TryParse(value.AsSpan(), style, provider, out decimal result));
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Fact]
+ public static void TryFormat()
+ {
+ using (new ThreadCultureChange(CultureInfo.InvariantCulture))
+ {
+ foreach (object[] testdata in ToString_TestData())
+ {
+ decimal localI = (decimal)testdata[0];
+ string localFormat = (string)testdata[1];
+ IFormatProvider localProvider = (IFormatProvider)testdata[2];
+ string localExpected = (string)testdata[3];
+
+ try
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[localExpected.Length];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected, new string(actual));
+
+ // Longer than needed
+ actual = new char[localExpected.Length + 1];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (localExpected.Length > 0)
+ {
+ actual = new char[localExpected.Length - 1];
+ Assert.False(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (localFormat != null)
+ {
+ // Upper localFormat
+ actual = new char[localExpected.Length];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat.ToUpperInvariant(), localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[localExpected.Length];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat.ToLowerInvariant(), localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected.ToLowerInvariant(), new string(actual));
+ }
+ }
+ catch (Exception exc)
+ {
+ throw new Exception($"Failed on `{localI}`, `{localFormat}`, `{localProvider}`, `{localExpected}`. {exc}");
+ }
+ }
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class DecimalTests
- {
- [Theory]
- [InlineData(MidpointRounding.ToEven - 1)]
- [InlineData(MidpointRounding.ToPositiveInfinity + 1)]
- public void Round_InvalidMidpointRounding_ThrowsArgumentException(MidpointRounding mode)
- {
- AssertExtensions.Throws<ArgumentException>("mode", () => decimal.Round(1, 2, mode));
- }
-
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "-123", 1, 3, NumberStyles.Number, null, 123m };
- yield return new object[] { "-123", 0, 3, NumberStyles.Number, null, -12m };
- yield return new object[] { 1000.ToString("N0"), 0, 4, NumberStyles.AllowThousands, null, 100m };
- yield return new object[] { 1000.ToString("N0"), 2, 3, NumberStyles.AllowThousands, null, 0m };
- yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, 123m };
- yield return new object[] { "1234567890123456789012345.678456", 1, 4, NumberStyles.Number, new NumberFormatInfo() { NumberDecimalSeparator = "." }, 2345m };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, decimal expected)
- {
- bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
- decimal result;
- if ((style & ~NumberStyles.Number) == 0 && style != NumberStyles.None)
- {
- // Use Parse(string) or Parse(string, IFormatProvider)
- if (isDefaultProvider)
- {
- Assert.True(decimal.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
-
- Assert.Equal(expected, decimal.Parse(value.AsSpan(offset, count)));
- }
-
- Assert.Equal(expected, decimal.Parse(value.AsSpan(offset, count), provider: provider));
- }
-
- Assert.Equal(expected, decimal.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(decimal.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- Assert.Throws(exceptionType, () => decimal.Parse(value.AsSpan(), style, provider));
-
- Assert.False(decimal.TryParse(value.AsSpan(), style, provider, out decimal result));
- Assert.Equal(0, result);
- }
- }
-
- [Fact]
- public static void TryFormat()
- {
- using (new ThreadCultureChange(CultureInfo.InvariantCulture))
- {
- foreach (object[] testdata in ToString_TestData())
- {
- decimal localI = (decimal)testdata[0];
- string localFormat = (string)testdata[1];
- IFormatProvider localProvider = (IFormatProvider)testdata[2];
- string localExpected = (string)testdata[3];
-
- try
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[localExpected.Length];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected, new string(actual));
-
- // Longer than needed
- actual = new char[localExpected.Length + 1];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected, new string(actual, 0, charsWritten));
-
- // Too short
- if (localExpected.Length > 0)
- {
- actual = new char[localExpected.Length - 1];
- Assert.False(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(0, charsWritten);
- }
-
- if (localFormat != null)
- {
- // Upper localFormat
- actual = new char[localExpected.Length];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat.ToUpperInvariant(), localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[localExpected.Length];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat.ToLowerInvariant(), localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected.ToLowerInvariant(), new string(actual));
- }
- }
- catch (Exception exc)
- {
- throw new Exception($"Failed on `{localI}`, `{localFormat}`, `{localProvider}`, `{localExpected}`. {exc}");
- }
- }
- }
- }
- }
-}
namespace System.Tests
{
- public partial class DoubleTests
+ public class DoubleTests
{
// NOTE: Consider duplicating any tests added here in SingleTests.cs
Assert.Throws<FormatException>(() => d.ToString("Y")); // Invalid format
Assert.Throws<FormatException>(() => d.ToString("Y", null)); // Invalid format
}
+
+ [Theory]
+ [InlineData(double.NegativeInfinity, false)] // Negative Infinity
+ [InlineData(double.MinValue, true)] // Min Negative Normal
+ [InlineData(-2.2250738585072014E-308, true)] // Max Negative Normal
+ [InlineData(-2.2250738585072009E-308, true)] // Min Negative Subnormal
+ [InlineData(-4.94065645841247E-324, true)] // Max Negative Subnormal
+ [InlineData(-0.0, true)] // Negative Zero
+ [InlineData(double.NaN, false)] // NaN
+ [InlineData(0.0, true)] // Positive Zero
+ [InlineData(4.94065645841247E-324, true)] // Min Positive Subnormal
+ [InlineData(2.2250738585072009E-308, true)] // Max Positive Subnormal
+ [InlineData(2.2250738585072014E-308, true)] // Min Positive Normal
+ [InlineData(double.MaxValue, true)] // Max Positive Normal
+ [InlineData(double.PositiveInfinity, false)] // Positive Infinity
+ public static void IsFinite(double d, bool expected)
+ {
+ Assert.Equal(expected, double.IsFinite(d));
+ }
+
+ [Theory]
+ [InlineData(double.NegativeInfinity, true)] // Negative Infinity
+ [InlineData(double.MinValue, true)] // Min Negative Normal
+ [InlineData(-2.2250738585072014E-308, true)] // Max Negative Normal
+ [InlineData(-2.2250738585072009E-308, true)] // Min Negative Subnormal
+ [InlineData(-4.94065645841247E-324, true)] // Max Negative Subnormal
+ [InlineData(-0.0, true)] // Negative Zero
+ [InlineData(double.NaN, true)] // NaN
+ [InlineData(0.0, false)] // Positive Zero
+ [InlineData(4.94065645841247E-324, false)] // Min Positive Subnormal
+ [InlineData(2.2250738585072009E-308, false)] // Max Positive Subnormal
+ [InlineData(2.2250738585072014E-308, false)] // Min Positive Normal
+ [InlineData(double.MaxValue, false)] // Max Positive Normal
+ [InlineData(double.PositiveInfinity, false)] // Positive Infinity
+ public static void IsNegative(double d, bool expected)
+ {
+ Assert.Equal(expected, double.IsNegative(d));
+ }
+
+ [Theory]
+ [InlineData(double.NegativeInfinity, false)] // Negative Infinity
+ [InlineData(double.MinValue, true)] // Min Negative Normal
+ [InlineData(-2.2250738585072014E-308, true)] // Max Negative Normal
+ [InlineData(-2.2250738585072009E-308, false)] // Min Negative Subnormal
+ [InlineData(-4.94065645841247E-324, false)] // Max Negative Subnormal
+ [InlineData(-0.0, false)] // Negative Zero
+ [InlineData(double.NaN, false)] // NaN
+ [InlineData(0.0, false)] // Positive Zero
+ [InlineData(4.94065645841247E-324, false)] // Min Positive Subnormal
+ [InlineData(2.2250738585072009E-308, false)] // Max Positive Subnormal
+ [InlineData(2.2250738585072014E-308, true)] // Min Positive Normal
+ [InlineData(double.MaxValue, true)] // Max Positive Normal
+ [InlineData(double.PositiveInfinity, false)] // Positive Infinity
+ public static void IsNormal(double d, bool expected)
+ {
+ Assert.Equal(expected, double.IsNormal(d));
+ }
+
+ [Theory]
+ [InlineData(double.NegativeInfinity, false)] // Negative Infinity
+ [InlineData(double.MinValue, false)] // Min Negative Normal
+ [InlineData(-2.2250738585072014E-308, false)] // Max Negative Normal
+ [InlineData(-2.2250738585072009E-308, true)] // Min Negative Subnormal
+ [InlineData(-4.94065645841247E-324, true)] // Max Negative Subnormal
+ [InlineData(-0.0, false)] // Negative Zero
+ [InlineData(double.NaN, false)] // NaN
+ [InlineData(0.0, false)] // Positive Zero
+ [InlineData(4.94065645841247E-324, true)] // Min Positive Subnormal
+ [InlineData(2.2250738585072009E-308, true)] // Max Positive Subnormal
+ [InlineData(2.2250738585072014E-308, false)] // Min Positive Normal
+ [InlineData(double.MaxValue, false)] // Max Positive Normal
+ [InlineData(double.PositiveInfinity, false)] // Positive Infinity
+ public static void IsSubnormal(double d, bool expected)
+ {
+ Assert.Equal(expected, double.IsSubnormal(d));
+ }
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ const NumberStyles DefaultStyle = NumberStyles.Float | NumberStyles.AllowThousands;
+ yield return new object[] { "-123", 0, 3, DefaultStyle, null, (double)-12 };
+ yield return new object[] { "-123", 1, 3, DefaultStyle, null, (double)123 };
+ yield return new object[] { "1E23", 0, 3, DefaultStyle, null, 1E2 };
+ yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, 123 };
+ yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, double.PositiveInfinity };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, double expected)
+ {
+ bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
+ double result;
+ if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None)
+ {
+ // Use Parse(string) or Parse(string, IFormatProvider)
+ if (isDefaultProvider)
+ {
+ Assert.True(double.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+
+ Assert.Equal(expected, double.Parse(value.AsSpan(offset, count)));
+ }
+
+ Assert.Equal(expected, double.Parse(value.AsSpan(offset, count), provider: provider));
+ }
+
+ Assert.Equal(expected, double.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(double.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ Assert.Throws(exceptionType, () => double.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(double.TryParse(value.AsSpan(), style, provider, out double result));
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Fact]
+ public static void TryFormat()
+ {
+ using (new ThreadCultureChange(CultureInfo.InvariantCulture))
+ {
+ foreach (var testdata in ToString_TestData_NotNetFramework())
+ {
+ double localI = (double)testdata[0];
+ string localFormat = (string)testdata[1];
+ IFormatProvider localProvider = (IFormatProvider)testdata[2];
+ string localExpected = (string)testdata[3];
+
+ try
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[localExpected.Length];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected, new string(actual));
+
+ // Longer than needed
+ actual = new char[localExpected.Length + 1];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (localExpected.Length > 0)
+ {
+ actual = new char[localExpected.Length - 1];
+ Assert.False(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(0, charsWritten);
+ }
+ }
+ catch (Exception exc)
+ {
+ throw new Exception($"Failed on `{localI}`, `{localFormat}`, `{localProvider}`, `{localExpected}`. {exc}");
+ }
+ }
+ }
+ }
+
+ public static IEnumerable<object[]> ToStringRoundtrip_TestData()
+ {
+ yield return new object[] { double.NegativeInfinity };
+ yield return new object[] { double.MinValue };
+ yield return new object[] { -Math.PI };
+ yield return new object[] { -Math.E };
+ yield return new object[] { -double.Epsilon };
+ yield return new object[] { -0.84551240822557006 };
+ yield return new object[] { -0.0 };
+ yield return new object[] { double.NaN };
+ yield return new object[] { 0.0 };
+ yield return new object[] { 0.84551240822557006 };
+ yield return new object[] { double.Epsilon };
+ yield return new object[] { Math.E };
+ yield return new object[] { Math.PI };
+ yield return new object[] { double.MaxValue };
+ yield return new object[] { double.PositiveInfinity };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToStringRoundtrip_TestData))]
+ public static void ToStringRoundtrip(double value)
+ {
+ double result = double.Parse(value.ToString());
+ Assert.Equal(BitConverter.DoubleToInt64Bits(value), BitConverter.DoubleToInt64Bits(result));
+ }
+
+ [Theory]
+ [MemberData(nameof(ToStringRoundtrip_TestData))]
+ public static void ToStringRoundtrip_R(double value)
+ {
+ double result = double.Parse(value.ToString("R"));
+ Assert.Equal(BitConverter.DoubleToInt64Bits(value), BitConverter.DoubleToInt64Bits(result));
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-#pragma warning disable xUnit1025 // reporting duplicate test cases due to not distinguishing 0.0 from -0.0, NaN from -NaN
-
-namespace System.Tests
-{
- public partial class DoubleTests
- {
- [Theory]
- [InlineData(double.NegativeInfinity, false)] // Negative Infinity
- [InlineData(double.MinValue, true)] // Min Negative Normal
- [InlineData(-2.2250738585072014E-308, true)] // Max Negative Normal
- [InlineData(-2.2250738585072009E-308, true)] // Min Negative Subnormal
- [InlineData(-4.94065645841247E-324, true)] // Max Negative Subnormal
- [InlineData(-0.0, true)] // Negative Zero
- [InlineData(double.NaN, false)] // NaN
- [InlineData(0.0, true)] // Positive Zero
- [InlineData(4.94065645841247E-324, true)] // Min Positive Subnormal
- [InlineData(2.2250738585072009E-308, true)] // Max Positive Subnormal
- [InlineData(2.2250738585072014E-308, true)] // Min Positive Normal
- [InlineData(double.MaxValue, true)] // Max Positive Normal
- [InlineData(double.PositiveInfinity, false)] // Positive Infinity
- public static void IsFinite(double d, bool expected)
- {
- Assert.Equal(expected, double.IsFinite(d));
- }
-
- [Theory]
- [InlineData(double.NegativeInfinity, true)] // Negative Infinity
- [InlineData(double.MinValue, true)] // Min Negative Normal
- [InlineData(-2.2250738585072014E-308, true)] // Max Negative Normal
- [InlineData(-2.2250738585072009E-308, true)] // Min Negative Subnormal
- [InlineData(-4.94065645841247E-324, true)] // Max Negative Subnormal
- [InlineData(-0.0, true)] // Negative Zero
- [InlineData(double.NaN, true)] // NaN
- [InlineData(0.0, false)] // Positive Zero
- [InlineData(4.94065645841247E-324, false)] // Min Positive Subnormal
- [InlineData(2.2250738585072009E-308, false)] // Max Positive Subnormal
- [InlineData(2.2250738585072014E-308, false)] // Min Positive Normal
- [InlineData(double.MaxValue, false)] // Max Positive Normal
- [InlineData(double.PositiveInfinity, false)] // Positive Infinity
- public static void IsNegative(double d, bool expected)
- {
- Assert.Equal(expected, double.IsNegative(d));
- }
-
- [Theory]
- [InlineData(double.NegativeInfinity, false)] // Negative Infinity
- [InlineData(double.MinValue, true)] // Min Negative Normal
- [InlineData(-2.2250738585072014E-308, true)] // Max Negative Normal
- [InlineData(-2.2250738585072009E-308, false)] // Min Negative Subnormal
- [InlineData(-4.94065645841247E-324, false)] // Max Negative Subnormal
- [InlineData(-0.0, false)] // Negative Zero
- [InlineData(double.NaN, false)] // NaN
- [InlineData(0.0, false)] // Positive Zero
- [InlineData(4.94065645841247E-324, false)] // Min Positive Subnormal
- [InlineData(2.2250738585072009E-308, false)] // Max Positive Subnormal
- [InlineData(2.2250738585072014E-308, true)] // Min Positive Normal
- [InlineData(double.MaxValue, true)] // Max Positive Normal
- [InlineData(double.PositiveInfinity, false)] // Positive Infinity
- public static void IsNormal(double d, bool expected)
- {
- Assert.Equal(expected, double.IsNormal(d));
- }
-
- [Theory]
- [InlineData(double.NegativeInfinity, false)] // Negative Infinity
- [InlineData(double.MinValue, false)] // Min Negative Normal
- [InlineData(-2.2250738585072014E-308, false)] // Max Negative Normal
- [InlineData(-2.2250738585072009E-308, true)] // Min Negative Subnormal
- [InlineData(-4.94065645841247E-324, true)] // Max Negative Subnormal
- [InlineData(-0.0, false)] // Negative Zero
- [InlineData(double.NaN, false)] // NaN
- [InlineData(0.0, false)] // Positive Zero
- [InlineData(4.94065645841247E-324, true)] // Min Positive Subnormal
- [InlineData(2.2250738585072009E-308, true)] // Max Positive Subnormal
- [InlineData(2.2250738585072014E-308, false)] // Min Positive Normal
- [InlineData(double.MaxValue, false)] // Max Positive Normal
- [InlineData(double.PositiveInfinity, false)] // Positive Infinity
- public static void IsSubnormal(double d, bool expected)
- {
- Assert.Equal(expected, double.IsSubnormal(d));
- }
-
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- const NumberStyles DefaultStyle = NumberStyles.Float | NumberStyles.AllowThousands;
- yield return new object[] { "-123", 0, 3, DefaultStyle, null, (double)-12 };
- yield return new object[] { "-123", 1, 3, DefaultStyle, null, (double)123 };
- yield return new object[] { "1E23", 0, 3, DefaultStyle, null, 1E2 };
- yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, 123 };
- yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, double.PositiveInfinity };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, double expected)
- {
- bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
- double result;
- if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None)
- {
- // Use Parse(string) or Parse(string, IFormatProvider)
- if (isDefaultProvider)
- {
- Assert.True(double.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
-
- Assert.Equal(expected, double.Parse(value.AsSpan(offset, count)));
- }
-
- Assert.Equal(expected, double.Parse(value.AsSpan(offset, count), provider: provider));
- }
-
- Assert.Equal(expected, double.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(double.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- Assert.Throws(exceptionType, () => double.Parse(value.AsSpan(), style, provider));
-
- Assert.False(double.TryParse(value.AsSpan(), style, provider, out double result));
- Assert.Equal(0, result);
- }
- }
-
- [Fact]
- public static void TryFormat()
- {
- using (new ThreadCultureChange(CultureInfo.InvariantCulture))
- {
- foreach (var testdata in ToString_TestData_NotNetFramework())
- {
- double localI = (double)testdata[0];
- string localFormat = (string)testdata[1];
- IFormatProvider localProvider = (IFormatProvider)testdata[2];
- string localExpected = (string)testdata[3];
-
- try
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[localExpected.Length];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected, new string(actual));
-
- // Longer than needed
- actual = new char[localExpected.Length + 1];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected, new string(actual, 0, charsWritten));
-
- // Too short
- if (localExpected.Length > 0)
- {
- actual = new char[localExpected.Length - 1];
- Assert.False(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(0, charsWritten);
- }
- }
- catch (Exception exc)
- {
- throw new Exception($"Failed on `{localI}`, `{localFormat}`, `{localProvider}`, `{localExpected}`. {exc}");
- }
- }
- }
- }
-
- public static IEnumerable<object[]> ToStringRoundtrip_TestData()
- {
- yield return new object[] { double.NegativeInfinity };
- yield return new object[] { double.MinValue };
- yield return new object[] { -Math.PI };
- yield return new object[] { -Math.E };
- yield return new object[] { -double.Epsilon };
- yield return new object[] { -0.84551240822557006 };
- yield return new object[] { -0.0 };
- yield return new object[] { double.NaN };
- yield return new object[] { 0.0 };
- yield return new object[] { 0.84551240822557006 };
- yield return new object[] { double.Epsilon };
- yield return new object[] { Math.E };
- yield return new object[] { Math.PI };
- yield return new object[] { double.MaxValue };
- yield return new object[] { double.PositiveInfinity };
- }
-
- [Theory]
- [MemberData(nameof(ToStringRoundtrip_TestData))]
- public static void ToStringRoundtrip(double value)
- {
- double result = double.Parse(value.ToString());
- Assert.Equal(BitConverter.DoubleToInt64Bits(value), BitConverter.DoubleToInt64Bits(result));
- }
-
- [Theory]
- [MemberData(nameof(ToStringRoundtrip_TestData))]
- public static void ToStringRoundtrip_R(double value)
- {
- double result = double.Parse(value.ToString("R"));
- Assert.Equal(BitConverter.DoubleToInt64Bits(value), BitConverter.DoubleToInt64Bits(result));
- }
- }
-}
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Reflection.Emit;
using Xunit;
namespace System.Tests
{
- public partial class EnumTests
+ public class EnumTests
{
public static IEnumerable<object[]> Parse_TestData()
{
Assert.Equal(expected, result);
Assert.Equal(expected, Enum.Parse(expected.GetType(), value));
+ Assert.Equal(expected, Enum.Parse<T>(value));
}
Assert.True(Enum.TryParse(value, ignoreCase, out result));
Assert.Equal(expected, result);
Assert.Equal(expected, Enum.Parse(expected.GetType(), value, ignoreCase));
+ Assert.Equal(expected, Enum.Parse<T>(value, ignoreCase));
}
public static IEnumerable<object[]> Parse_Invalid_TestData()
private static void Parse_Generic_Invalid<T>(Type enumType, string value, bool ignoreCase, Type exceptionType) where T : struct
{
- T result;
+ object result = null;
if (!ignoreCase)
{
- Assert.False(Enum.TryParse(value, out result));
- Assert.Equal(default(T), result);
-
- Assert.Throws(exceptionType, () => Enum.Parse(enumType, value));
+ if (enumType != null && enumType.IsEnum)
+ {
+ Assert.False(Enum.TryParse(enumType, value, out result));
+ Assert.Equal(default(object), result);
+
+ Assert.Throws(exceptionType, () => Enum.Parse<T>(value));
+ }
+ else
+ {
+ Assert.Throws(exceptionType, () => Enum.TryParse(enumType, value, out result));
+ Assert.Equal(default(object), result);
+ }
}
- Assert.False(Enum.TryParse(value, ignoreCase, out result));
- Assert.Equal(default(T), result);
+ if (enumType != null && enumType.IsEnum)
+ {
+ Assert.False(Enum.TryParse(enumType, value, ignoreCase, out result));
+ Assert.Equal(default(object), result);
- Assert.Throws(exceptionType, () => Enum.Parse(enumType, value, ignoreCase));
+ Assert.Throws(exceptionType, () => Enum.Parse<T>(value, ignoreCase));
+ }
+ else
+ {
+ Assert.Throws(exceptionType, () => Enum.TryParse(enumType, value, ignoreCase, out result));
+ Assert.Equal(default(object), result);
+ }
}
public static IEnumerable<object[]> GetName_TestData()
Assert.Throws<FormatException>(() => Enum.Format(typeof(SimpleEnum), SimpleEnum.Red, " \t")); // Format is whitespace
Assert.Throws<FormatException>(() => Enum.Format(typeof(SimpleEnum), SimpleEnum.Red, "t")); // No such format
}
+
+ public static IEnumerable<object[]> UnsupportedEnumType_TestData()
+ {
+#if NETCOREAPP
+ yield return new object[] { s_floatEnumType, 1.0f };
+ yield return new object[] { s_doubleEnumType, 1.0 };
+ yield return new object[] { s_intPtrEnumType, (IntPtr)1 };
+ yield return new object[] { s_uintPtrEnumType, (UIntPtr)1 };
+#else
+ return Array.Empty<object[]>();
+#endif
+ }
+
+ [Theory]
+ [MemberData(nameof(UnsupportedEnumType_TestData))]
+ public static void GetName_Unsupported_ThrowsArgumentException(Type enumType, object value)
+ {
+ AssertExtensions.Throws<ArgumentException>("value", () => Enum.GetName(enumType, value));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnsupportedEnumType_TestData))]
+ public static void IsDefined_UnsupportedEnumType_ThrowsInvalidOperationException(Type enumType, object value)
+ {
+ Exception ex = Assert.ThrowsAny<Exception>(() => Enum.IsDefined(enumType, value));
+ string exName = ex.GetType().Name;
+ Assert.True(exName == nameof(InvalidOperationException) || exName == "ContractException");
+ }
+
+ public static IEnumerable<object[]> UnsupportedEnum_TestData()
+ {
+ yield return new object[] { Enum.ToObject(s_floatEnumType, 1) };
+ yield return new object[] { Enum.ToObject(s_doubleEnumType, 2) };
+ yield return new object[] { Enum.ToObject(s_intPtrEnumType, 1) };
+ yield return new object[] { Enum.ToObject(s_uintPtrEnumType, 2) };
+ }
+
+ [Theory]
+ [MemberData(nameof(UnsupportedEnum_TestData))]
+ public static void ToString_UnsupportedEnumType_ThrowsArgumentException(Enum e)
+ {
+ Exception formatXException = Assert.ThrowsAny<Exception>(() => e.ToString("X"));
+ string formatXExceptionName = formatXException.GetType().Name;
+ Assert.True(formatXExceptionName == nameof(InvalidOperationException) || formatXExceptionName == "ContractException");
+ }
+
+ [Theory]
+ [MemberData(nameof(UnsupportedEnumType_TestData))]
+ public static void Format_UnsupportedEnumType_ThrowsArgumentException(Type enumType, object value)
+ {
+ Exception formatGException = Assert.ThrowsAny<Exception>(() => Enum.Format(enumType, value, "G"));
+ string formatGExceptionName = formatGException.GetType().Name;
+ Assert.True(formatGExceptionName == nameof(InvalidOperationException) || formatGExceptionName == "ContractException");
+
+ Exception formatXException = Assert.ThrowsAny<Exception>(() => Enum.Format(enumType, value, "X"));
+ string formatXExceptionName = formatXException.GetType().Name;
+ Assert.True(formatXExceptionName == nameof(InvalidOperationException) || formatXExceptionName == "ContractException");
+
+ Exception formatFException = Assert.ThrowsAny<Exception>(() => Enum.Format(enumType, value, "F"));
+ string formatFExceptionName = formatFException.GetType().Name;
+ Assert.True(formatFExceptionName == nameof(InvalidOperationException) || formatFExceptionName == "ContractException");
+ }
+
+ private static EnumBuilder GetNonRuntimeEnumTypeBuilder(Type underlyingType)
+ {
+ AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Name"), AssemblyBuilderAccess.Run);
+ ModuleBuilder module = assembly.DefineDynamicModule("Name");
+
+ return module.DefineEnum("TestName_" + underlyingType.Name, TypeAttributes.Public, underlyingType);
+ }
+
+ private static Type s_boolEnumType = GetBoolEnumType();
+ private static Type GetBoolEnumType()
+ {
+ EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(bool));
+ enumBuilder.DefineLiteral("Value1", true);
+ enumBuilder.DefineLiteral("Value2", false);
+
+ return enumBuilder.CreateTypeInfo().AsType();
+ }
+
+ private static Type s_charEnumType = GetCharEnumType();
+ private static Type GetCharEnumType()
+ {
+ EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(char));
+ enumBuilder.DefineLiteral("Value1", (char)1);
+ enumBuilder.DefineLiteral("Value2", (char)2);
+
+ enumBuilder.DefineLiteral("Value0x3f06", (char)0x3f06);
+ enumBuilder.DefineLiteral("Value0x3000", (char)0x3000);
+ enumBuilder.DefineLiteral("Value0x0f06", (char)0x0f06);
+ enumBuilder.DefineLiteral("Value0x1000", (char)0x1000);
+ enumBuilder.DefineLiteral("Value0x0000", (char)0x0000);
+ enumBuilder.DefineLiteral("Value0x0010", (char)0x0010);
+ enumBuilder.DefineLiteral("Value0x3f16", (char)0x3f16);
+
+ return enumBuilder.CreateTypeInfo().AsType();
+ }
+
+ private static Type s_floatEnumType = GetFloatEnumType();
+ private static Type GetFloatEnumType()
+ {
+ EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(float));
+ enumBuilder.DefineLiteral("Value1", 1.0f);
+ enumBuilder.DefineLiteral("Value2", 2.0f);
+
+ enumBuilder.DefineLiteral("Value0x3f06", (float)0x3f06);
+ enumBuilder.DefineLiteral("Value0x3000", (float)0x3000);
+ enumBuilder.DefineLiteral("Value0x0f06", (float)0x0f06);
+ enumBuilder.DefineLiteral("Value0x1000", (float)0x1000);
+ enumBuilder.DefineLiteral("Value0x0000", (float)0x0000);
+ enumBuilder.DefineLiteral("Value0x0010", (float)0x0010);
+ enumBuilder.DefineLiteral("Value0x3f16", (float)0x3f16);
+
+ return enumBuilder.CreateTypeInfo().AsType();
+ }
+
+ private static Type s_doubleEnumType = GetDoubleEnumType();
+ private static Type GetDoubleEnumType()
+ {
+ EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(double));
+ enumBuilder.DefineLiteral("Value1", 1.0);
+ enumBuilder.DefineLiteral("Value2", 2.0);
+
+ enumBuilder.DefineLiteral("Value0x3f06", (double)0x3f06);
+ enumBuilder.DefineLiteral("Value0x3000", (double)0x3000);
+ enumBuilder.DefineLiteral("Value0x0f06", (double)0x0f06);
+ enumBuilder.DefineLiteral("Value0x1000", (double)0x1000);
+ enumBuilder.DefineLiteral("Value0x0000", (double)0x0000);
+ enumBuilder.DefineLiteral("Value0x0010", (double)0x0010);
+ enumBuilder.DefineLiteral("Value0x3f16", (double)0x3f16);
+
+ return enumBuilder.CreateTypeInfo().AsType();
+ }
+
+ private static Type s_intPtrEnumType = GetIntPtrEnumType();
+ private static Type GetIntPtrEnumType()
+ {
+ EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(IntPtr));
+
+ return enumBuilder.CreateTypeInfo().AsType();
+ }
+
+ private static Type s_uintPtrEnumType = GetUIntPtrEnumType();
+ private static Type GetUIntPtrEnumType()
+ {
+ EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(UIntPtr));
+
+ return enumBuilder.CreateTypeInfo().AsType();
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class EnumTests
- {
- [Theory]
- [MemberData(nameof(Parse_TestData))]
- public static void Parse_NetCoreApp11<T>(string value, bool ignoreCase, T expected) where T : struct
- {
- object result;
- if (!ignoreCase)
- {
- Assert.True(Enum.TryParse(expected.GetType(), value, out result));
- Assert.Equal(expected, result);
-
- Assert.Equal(expected, Enum.Parse<T>(value));
- }
-
- Assert.True(Enum.TryParse(expected.GetType(), value, ignoreCase, out result));
- Assert.Equal(expected, result);
-
- Assert.Equal(expected, Enum.Parse<T>(value, ignoreCase));
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Invalid_NetCoreApp11(Type enumType, string value, bool ignoreCase, Type exceptionType)
- {
- Type typeArgument = enumType == null || !enumType.IsValueType ? typeof(SimpleEnum) : enumType;
- MethodInfo parseMethod = typeof(EnumTests).GetTypeInfo().GetMethod(nameof(Parse_Generic_Invalid_NetCoreApp11), BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(typeArgument);
- parseMethod.Invoke(null, new object[] { enumType, value, ignoreCase, exceptionType });
- }
-
- private static void Parse_Generic_Invalid_NetCoreApp11<T>(Type enumType, string value, bool ignoreCase, Type exceptionType) where T : struct
- {
- object result = null;
- if (!ignoreCase)
- {
- if (enumType != null && enumType.IsEnum)
- {
- Assert.False(Enum.TryParse(enumType, value, out result));
- Assert.Equal(default(object), result);
-
- Assert.Throws(exceptionType, () => Enum.Parse<T>(value));
- }
- else
- {
- Assert.Throws(exceptionType, () => Enum.TryParse(enumType, value, out result));
- Assert.Equal(default(object), result);
- }
- }
-
- if (enumType != null && enumType.IsEnum)
- {
- Assert.False(Enum.TryParse(enumType, value, ignoreCase, out result));
- Assert.Equal(default(object), result);
-
- Assert.Throws(exceptionType, () => Enum.Parse<T>(value, ignoreCase));
- }
- else
- {
- Assert.Throws(exceptionType, () => Enum.TryParse(enumType, value, ignoreCase, out result));
- Assert.Equal(default(object), result);
- }
- }
-
- public static IEnumerable<object[]> UnsupportedEnumType_TestData()
- {
-#if NETCOREAPP
- yield return new object[] { s_floatEnumType, 1.0f };
- yield return new object[] { s_doubleEnumType, 1.0 };
- yield return new object[] { s_intPtrEnumType, (IntPtr)1 };
- yield return new object[] { s_uintPtrEnumType, (UIntPtr)1 };
-#else
- return Array.Empty<object[]>();
-#endif
- }
-
- [Theory]
- [MemberData(nameof(UnsupportedEnumType_TestData))]
- public static void GetName_Unsupported_ThrowsArgumentException(Type enumType, object value)
- {
- AssertExtensions.Throws<ArgumentException>("value", () => Enum.GetName(enumType, value));
- }
-
- [Theory]
- [MemberData(nameof(UnsupportedEnumType_TestData))]
- public static void IsDefined_UnsupportedEnumType_ThrowsInvalidOperationException(Type enumType, object value)
- {
- Exception ex = Assert.ThrowsAny<Exception>(() => Enum.IsDefined(enumType, value));
- string exName = ex.GetType().Name;
- Assert.True(exName == nameof(InvalidOperationException) || exName == "ContractException");
- }
-
- public static IEnumerable<object[]> UnsupportedEnum_TestData()
- {
-#if NETCOREAPP
- yield return new object[] { Enum.ToObject(s_floatEnumType, 1) };
- yield return new object[] { Enum.ToObject(s_doubleEnumType, 2) };
- yield return new object[] { Enum.ToObject(s_intPtrEnumType, 1) };
- yield return new object[] { Enum.ToObject(s_uintPtrEnumType, 2) };
-#else
- return Array.Empty<object[]>();
-#endif
- }
-
- [Theory]
- [MemberData(nameof(UnsupportedEnum_TestData))]
- public static void ToString_UnsupportedEnumType_ThrowsArgumentException(Enum e)
- {
- Exception formatXException = Assert.ThrowsAny<Exception>(() => e.ToString("X"));
- string formatXExceptionName = formatXException.GetType().Name;
- Assert.True(formatXExceptionName == nameof(InvalidOperationException) || formatXExceptionName == "ContractException");
- }
-
- [Theory]
- [MemberData(nameof(UnsupportedEnumType_TestData))]
- public static void Format_UnsupportedEnumType_ThrowsArgumentException(Type enumType, object value)
- {
- Exception formatGException = Assert.ThrowsAny<Exception>(() => Enum.Format(enumType, value, "G"));
- string formatGExceptionName = formatGException.GetType().Name;
- Assert.True(formatGExceptionName == nameof(InvalidOperationException) || formatGExceptionName == "ContractException");
-
- Exception formatXException = Assert.ThrowsAny<Exception>(() => Enum.Format(enumType, value, "X"));
- string formatXExceptionName = formatXException.GetType().Name;
- Assert.True(formatXExceptionName == nameof(InvalidOperationException) || formatXExceptionName == "ContractException");
-
- Exception formatFException = Assert.ThrowsAny<Exception>(() => Enum.Format(enumType, value, "F"));
- string formatFExceptionName = formatFException.GetType().Name;
- Assert.True(formatFExceptionName == nameof(InvalidOperationException) || formatFExceptionName == "ContractException");
- }
-
- private static EnumBuilder GetNonRuntimeEnumTypeBuilder(Type underlyingType)
- {
- AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Name"), AssemblyBuilderAccess.Run);
- ModuleBuilder module = assembly.DefineDynamicModule("Name");
-
- return module.DefineEnum("TestName_" + underlyingType.Name, TypeAttributes.Public, underlyingType);
- }
-
- private static Type s_boolEnumType = GetBoolEnumType();
- private static Type GetBoolEnumType()
- {
- EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(bool));
- enumBuilder.DefineLiteral("Value1", true);
- enumBuilder.DefineLiteral("Value2", false);
-
- return enumBuilder.CreateTypeInfo().AsType();
- }
-
- private static Type s_charEnumType = GetCharEnumType();
- private static Type GetCharEnumType()
- {
- EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(char));
- enumBuilder.DefineLiteral("Value1", (char)1);
- enumBuilder.DefineLiteral("Value2", (char)2);
-
- enumBuilder.DefineLiteral("Value0x3f06", (char)0x3f06);
- enumBuilder.DefineLiteral("Value0x3000", (char)0x3000);
- enumBuilder.DefineLiteral("Value0x0f06", (char)0x0f06);
- enumBuilder.DefineLiteral("Value0x1000", (char)0x1000);
- enumBuilder.DefineLiteral("Value0x0000", (char)0x0000);
- enumBuilder.DefineLiteral("Value0x0010", (char)0x0010);
- enumBuilder.DefineLiteral("Value0x3f16", (char)0x3f16);
-
- return enumBuilder.CreateTypeInfo().AsType();
- }
-
- private static Type s_floatEnumType = GetFloatEnumType();
- private static Type GetFloatEnumType()
- {
- EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(float));
- enumBuilder.DefineLiteral("Value1", 1.0f);
- enumBuilder.DefineLiteral("Value2", 2.0f);
-
- enumBuilder.DefineLiteral("Value0x3f06", (float)0x3f06);
- enumBuilder.DefineLiteral("Value0x3000", (float)0x3000);
- enumBuilder.DefineLiteral("Value0x0f06", (float)0x0f06);
- enumBuilder.DefineLiteral("Value0x1000", (float)0x1000);
- enumBuilder.DefineLiteral("Value0x0000", (float)0x0000);
- enumBuilder.DefineLiteral("Value0x0010", (float)0x0010);
- enumBuilder.DefineLiteral("Value0x3f16", (float)0x3f16);
-
- return enumBuilder.CreateTypeInfo().AsType();
- }
-
- private static Type s_doubleEnumType = GetDoubleEnumType();
- private static Type GetDoubleEnumType()
- {
- EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(double));
- enumBuilder.DefineLiteral("Value1", 1.0);
- enumBuilder.DefineLiteral("Value2", 2.0);
-
- enumBuilder.DefineLiteral("Value0x3f06", (double)0x3f06);
- enumBuilder.DefineLiteral("Value0x3000", (double)0x3000);
- enumBuilder.DefineLiteral("Value0x0f06", (double)0x0f06);
- enumBuilder.DefineLiteral("Value0x1000", (double)0x1000);
- enumBuilder.DefineLiteral("Value0x0000", (double)0x0000);
- enumBuilder.DefineLiteral("Value0x0010", (double)0x0010);
- enumBuilder.DefineLiteral("Value0x3f16", (double)0x3f16);
-
- return enumBuilder.CreateTypeInfo().AsType();
- }
-
- private static Type s_intPtrEnumType = GetIntPtrEnumType();
- private static Type GetIntPtrEnumType()
- {
- EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(IntPtr));
-
- return enumBuilder.CreateTypeInfo().AsType();
- }
-
- private static Type s_uintPtrEnumType = GetUIntPtrEnumType();
- private static Type GetUIntPtrEnumType()
- {
- EnumBuilder enumBuilder = GetNonRuntimeEnumTypeBuilder(typeof(UIntPtr));
-
- return enumBuilder.CreateTypeInfo().AsType();
- }
- }
-}
namespace System.Tests
{
- public partial class FormattableStringTests
+ public class FormattableStringTests
{
[Fact]
public static void Invariant_Null_ThrowsArgumentNullException()
}
}
+ [Fact]
+ public static void CurrentCulture_ImplicityAndExplicitMethodsReturnSameString()
+ {
+ double d = 123.456;
+ string text1 = $"This will be formatted using current culture {d}";
+ string text2 = FormattableString.CurrentCulture($"This will be formatted using current culture {d}");
+ Assert.Equal(text1, text2);
+ }
+
+ [Fact]
+ public static void CurrentCulture_Null_ThrowsArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("formattable", () => FormattableString.CurrentCulture(null));
+ }
+
+ [Fact]
+ public static void CurrentCulture_DutchCulture_FormatsDoubleBasedOnCurrentCulture()
+ {
+ var dutchCulture = new CultureInfo("nl");
+ using (new ThreadCultureChange(dutchCulture))
+ {
+ double d = 123.456;
+ string expected = string.Format(dutchCulture, "Dutch decimal separator is comma {0}", d);
+ string actual = FormattableString.CurrentCulture($"Dutch decimal separator is comma {d}");
+ Assert.Equal(expected, actual);
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Globalization;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class FormattableStringTests
- {
- [Fact]
- public static void CurrentCulture_ImplicityAndExplicitMethodsReturnSameString()
- {
- double d = 123.456;
- string text1 = $"This will be formatted using current culture {d}";
- string text2 = FormattableString.CurrentCulture($"This will be formatted using current culture {d}");
- Assert.Equal(text1, text2);
- }
-
- [Fact]
- public static void CurrentCulture_Null_ThrowsArgumentNullException()
- {
- AssertExtensions.Throws<ArgumentNullException>("formattable", () => FormattableString.CurrentCulture(null));
- }
-
- [Fact]
- public static void CurrentCulture_DutchCulture_FormatsDoubleBasedOnCurrentCulture()
- {
- var dutchCulture = new CultureInfo("nl");
- using (new ThreadCultureChange(dutchCulture))
- {
- double d = 123.456;
- string expected = string.Format(dutchCulture, "Dutch decimal separator is comma {0}", d);
- string actual = FormattableString.CurrentCulture($"Dutch decimal separator is comma {d}");
- Assert.Equal(expected, actual);
- }
- }
- }
-}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.Runtime;
namespace System.Tests
{
- public static partial class GCTests
+ public static class GCTests
{
private static bool s_is32Bits = IntPtr.Size == 4; // Skip IntPtr tests on 32-bit platforms
Thread.Sleep(500);
GC.CancelFullGCNotification();
}
+
+ [Theory]
+ [InlineData(1000)]
+ [InlineData(100000)]
+ public static void GetAllocatedBytesForCurrentThread(int size)
+ {
+ long start = GC.GetAllocatedBytesForCurrentThread();
+
+ GC.KeepAlive(new string('a', size));
+
+ long end = GC.GetAllocatedBytesForCurrentThread();
+
+ Assert.True((end - start) > size, $"Allocated too little: start: {start} end: {end} size: {size}");
+ Assert.True((end - start) < 5 * size, $"Allocated too much: start: {start} end: {end} size: {size}");
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArmProcess))] // [ActiveIssue(37378)]
+ public static void GetGCMemoryInfo()
+ {
+ RemoteExecutor.Invoke(() =>
+ {
+ // Allows to update the value returned by GC.GetGCMemoryInfo
+ GC.Collect();
+
+ GCMemoryInfo memoryInfo1 = GC.GetGCMemoryInfo();
+
+ Assert.InRange(memoryInfo1.HighMemoryLoadThresholdBytes, 1, long.MaxValue);
+ Assert.InRange(memoryInfo1.MemoryLoadBytes, 1, long.MaxValue);
+ Assert.InRange(memoryInfo1.TotalAvailableMemoryBytes, 1, long.MaxValue);
+ Assert.InRange(memoryInfo1.HeapSizeBytes, 1, long.MaxValue);
+ Assert.InRange(memoryInfo1.FragmentedBytes, 0, long.MaxValue);
+
+ GCHandle[] gch = new GCHandle[64 * 1024];
+ for (int i = 0; i < gch.Length * 2; ++i)
+ {
+ byte[] arr = new byte[64];
+ if (i % 2 == 0)
+ {
+ gch[i / 2] = GCHandle.Alloc(arr, GCHandleType.Pinned);
+ }
+ }
+
+ // Allows to update the value returned by GC.GetGCMemoryInfo
+ GC.Collect();
+
+ GCMemoryInfo memoryInfo2 = GC.GetGCMemoryInfo();
+
+ string scenario = null;
+ try
+ {
+ scenario = nameof(memoryInfo2.HighMemoryLoadThresholdBytes);
+ Assert.Equal(memoryInfo2.HighMemoryLoadThresholdBytes, memoryInfo1.HighMemoryLoadThresholdBytes);
+
+ // Even though we have allocated, the overall load may decrease or increase depending what other processes are doing.
+ // It cannot go above total available though.
+ scenario = nameof(memoryInfo2.MemoryLoadBytes);
+ Assert.InRange(memoryInfo2.MemoryLoadBytes, 1, memoryInfo1.TotalAvailableMemoryBytes);
+
+ scenario = nameof(memoryInfo2.TotalAvailableMemoryBytes);
+ Assert.Equal(memoryInfo2.TotalAvailableMemoryBytes, memoryInfo1.TotalAvailableMemoryBytes);
+
+ scenario = nameof(memoryInfo2.HeapSizeBytes);
+ Assert.InRange(memoryInfo2.HeapSizeBytes, memoryInfo1.HeapSizeBytes + 1, long.MaxValue);
+
+ scenario = nameof(memoryInfo2.FragmentedBytes);
+ Assert.InRange(memoryInfo2.FragmentedBytes, memoryInfo1.FragmentedBytes + 1, long.MaxValue);
+
+ scenario = null;
+ }
+ finally
+ {
+ if (scenario != null)
+ {
+ System.Console.WriteLine("FAILED: " + scenario);
+ }
+ }
+ }).Dispose();
+ }
+
+ [Fact]
+ public static void GetTotalAllocatedBytes()
+ {
+ byte[] stash;
+
+ long CallGetTotalAllocatedBytesAndCheck(long previous, out long differenceBetweenPreciseAndImprecise)
+ {
+ long precise = GC.GetTotalAllocatedBytes(true);
+ long imprecise = GC.GetTotalAllocatedBytes(false);
+
+ if (precise <= 0)
+ {
+ throw new Exception($"Bytes allocated is not positive, this is unlikely. precise = {precise}");
+ }
+
+ if (imprecise < precise)
+ {
+ throw new Exception($"Imprecise total bytes allocated less than precise, imprecise is required to be a conservative estimate (that estimates high). imprecise = {imprecise}, precise = {precise}");
+ }
+
+ if (previous > precise)
+ {
+ throw new Exception($"Expected more memory to be allocated. previous = {previous}, precise = {precise}, difference = {previous - precise}");
+ }
+
+ differenceBetweenPreciseAndImprecise = imprecise - precise;
+ return precise;
+ }
+
+ long CallGetTotalAllocatedBytes(long previous)
+ {
+ long differenceBetweenPreciseAndImprecise;
+ previous = CallGetTotalAllocatedBytesAndCheck(previous, out differenceBetweenPreciseAndImprecise);
+ stash = new byte[differenceBetweenPreciseAndImprecise];
+ previous = CallGetTotalAllocatedBytesAndCheck(previous, out differenceBetweenPreciseAndImprecise);
+ return previous;
+ }
+
+ long previous = 0;
+
+ for (int i = 0; i < 1000; ++i)
+ {
+ stash = new byte[1234];
+ previous = CallGetTotalAllocatedBytes(previous);
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-namespace System.Tests
-{
- public static partial class GCTests
- {
- [Theory]
- [InlineData(1000)]
- [InlineData(100000)]
- public static void GetAllocatedBytesForCurrentThread(int size)
- {
- long start = GC.GetAllocatedBytesForCurrentThread();
-
- GC.KeepAlive(new string('a', size));
-
- long end = GC.GetAllocatedBytesForCurrentThread();
-
- Assert.True((end - start) > size, $"Allocated too little: start: {start} end: {end} size: {size}");
- Assert.True((end - start) < 5 * size, $"Allocated too much: start: {start} end: {end} size: {size}");
- }
-
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArmProcess))] // [ActiveIssue(37378)]
- public static void GetGCMemoryInfo()
- {
- RemoteExecutor.Invoke(() =>
- {
- // Allows to update the value returned by GC.GetGCMemoryInfo
- GC.Collect();
-
- GCMemoryInfo memoryInfo1 = GC.GetGCMemoryInfo();
-
- Assert.InRange(memoryInfo1.HighMemoryLoadThresholdBytes, 1, long.MaxValue);
- Assert.InRange(memoryInfo1.MemoryLoadBytes, 1, long.MaxValue);
- Assert.InRange(memoryInfo1.TotalAvailableMemoryBytes, 1, long.MaxValue);
- Assert.InRange(memoryInfo1.HeapSizeBytes, 1, long.MaxValue);
- Assert.InRange(memoryInfo1.FragmentedBytes, 0, long.MaxValue);
-
- GCHandle[] gch = new GCHandle[64 * 1024];
- for (int i = 0; i < gch.Length * 2; ++i)
- {
- byte[] arr = new byte[64];
- if (i % 2 == 0)
- {
- gch[i / 2] = GCHandle.Alloc(arr, GCHandleType.Pinned);
- }
- }
-
- // Allows to update the value returned by GC.GetGCMemoryInfo
- GC.Collect();
-
- GCMemoryInfo memoryInfo2 = GC.GetGCMemoryInfo();
-
- string scenario = null;
- try
- {
- scenario = nameof(memoryInfo2.HighMemoryLoadThresholdBytes);
- Assert.Equal(memoryInfo2.HighMemoryLoadThresholdBytes, memoryInfo1.HighMemoryLoadThresholdBytes);
-
- // Even though we have allocated, the overall load may decrease or increase depending what other processes are doing.
- // It cannot go above total available though.
- scenario = nameof(memoryInfo2.MemoryLoadBytes);
- Assert.InRange(memoryInfo2.MemoryLoadBytes, 1, memoryInfo1.TotalAvailableMemoryBytes);
-
- scenario = nameof(memoryInfo2.TotalAvailableMemoryBytes);
- Assert.Equal(memoryInfo2.TotalAvailableMemoryBytes, memoryInfo1.TotalAvailableMemoryBytes);
-
- scenario = nameof(memoryInfo2.HeapSizeBytes);
- Assert.InRange(memoryInfo2.HeapSizeBytes, memoryInfo1.HeapSizeBytes + 1, long.MaxValue);
-
- scenario = nameof(memoryInfo2.FragmentedBytes);
- Assert.InRange(memoryInfo2.FragmentedBytes, memoryInfo1.FragmentedBytes + 1, long.MaxValue);
-
- scenario = null;
- }
- finally
- {
- if (scenario != null)
- {
- System.Console.WriteLine("FAILED: " + scenario);
- }
- }
- }).Dispose();
- }
-
- [Fact]
- public static void GetTotalAllocatedBytes()
- {
- byte[] stash;
-
- long CallGetTotalAllocatedBytesAndCheck(long previous, out long differenceBetweenPreciseAndImprecise)
- {
- long precise = GC.GetTotalAllocatedBytes(true);
- long imprecise = GC.GetTotalAllocatedBytes(false);
-
- if (precise <= 0)
- {
- throw new Exception($"Bytes allocated is not positive, this is unlikely. precise = {precise}");
- }
-
- if (imprecise < precise)
- {
- throw new Exception($"Imprecise total bytes allocated less than precise, imprecise is required to be a conservative estimate (that estimates high). imprecise = {imprecise}, precise = {precise}");
- }
-
- if (previous > precise)
- {
- throw new Exception($"Expected more memory to be allocated. previous = {previous}, precise = {precise}, difference = {previous - precise}");
- }
-
- differenceBetweenPreciseAndImprecise = imprecise - precise;
- return precise;
- }
-
- long CallGetTotalAllocatedBytes(long previous)
- {
- long differenceBetweenPreciseAndImprecise;
- previous = CallGetTotalAllocatedBytesAndCheck(previous, out differenceBetweenPreciseAndImprecise);
- stash = new byte[differenceBetweenPreciseAndImprecise];
- previous = CallGetTotalAllocatedBytesAndCheck(previous, out differenceBetweenPreciseAndImprecise);
- return previous;
- }
-
- long previous = 0;
-
- for (int i = 0; i < 1000; ++i)
- {
- stash = new byte[1234];
- previous = CallGetTotalAllocatedBytes(previous);
- }
- }
- }
-}
namespace System.Tests
{
- public static partial class GuidTests
+ public static class GuidTests
{
private static readonly Guid s_testGuid = new Guid("a8a110d5-fc49-43c5-bf46-802db8f843ff");
private static readonly Guid s_fullGuid = new Guid(uint.MaxValue, ushort.MaxValue, ushort.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
{
Assert.Equal(expected, Math.Sign(guid.CompareTo(obj)));
}
+
+ [Theory]
+ [MemberData(nameof(Ctor_ByteArray_TestData))]
+ public static void Ctor_ReadOnlySpan(byte[] b, Guid expected)
+ {
+ Assert.Equal(expected, new Guid(new ReadOnlySpan<byte>(b)));
+ }
+
+ [Theory]
+ [InlineData(15)]
+ [InlineData(17)]
+ public static void CtorSpan_InvalidLengthByteArray_ThrowsArgumentException(int length)
+ {
+ AssertExtensions.Throws<ArgumentException>("b", null, () => new Guid(new ReadOnlySpan<byte>(new byte[length])));
+ }
+
+ [Theory]
+ [MemberData(nameof(Ctor_ByteArray_TestData))]
+ public static void TryWriteBytes_ValidLength_ReturnsTrue(byte[] b, Guid guid)
+ {
+ var bytes = new byte[16];
+ Assert.True(guid.TryWriteBytes(new Span<byte>(bytes)));
+ Assert.Equal(b, bytes);
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(15)]
+ public static void TryWriteBytes_LengthTooShort_ReturnsFalse(int length)
+ {
+ Assert.False(s_testGuid.TryWriteBytes(new Span<byte>(new byte[length])));
+ }
+
+ [Theory]
+ [MemberData(nameof(InvalidFormat_TestData))]
+ public static void TryFormat_InvalidFormat_ThrowsFormatException(string format)
+ {
+ Assert.Throws<FormatException>(() => s_testGuid.TryFormat(new Span<char>(), out int charsWritten, format));
+ Assert.Throws<FormatException>(() => s_testGuid.TryFormat(new Span<char>(), out int charsWritten, format.ToUpperInvariant()));
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat_LengthTooSmall_ReturnsFalse(Guid guid, string format, string expected)
+ {
+ _ = expected;
+ Assert.False(guid.TryFormat(new Span<char>(new char[guid.ToString(format).Length - 1]), out int charsWritten, format));
+ Assert.Equal(0, charsWritten);
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat_CharsWritten_EqualsZero_WhenSpanTooSmall(Guid guid, string format, string expected)
+ {
+ _ = expected;
+ Assert.False(guid.TryFormat(new Span<char>(new char[guid.ToString(format).Length - 1]), out int charsWritten, format));
+ Assert.Equal(0, charsWritten);
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat_ValidLength_ReturnsTrue(Guid guid, string format, string expected)
+ {
+ char[] chars = new char[guid.ToString(format).Length];
+ Assert.True(guid.TryFormat(new Span<char>(chars), out int charsWritten, format));
+ Assert.Equal(chars, expected.ToCharArray());
+ }
+
+ [Theory]
+ [MemberData(nameof(GuidStrings_Valid_TestData))]
+ public static void Parse_Span_ValidInput_Success(string input, string format, Guid expected)
+ {
+ Assert.Equal(expected, Guid.Parse(input.AsSpan()));
+ Assert.Equal(expected, Guid.ParseExact(input.AsSpan(), format.ToUpperInvariant()));
+ Assert.Equal(expected, Guid.ParseExact(input.AsSpan(), format.ToLowerInvariant())); // Format should be case insensitive
+
+ Guid result;
+
+ Assert.True(Guid.TryParse(input.AsSpan(), out result));
+ Assert.Equal(expected, result);
+
+ Assert.True(Guid.TryParseExact(input.AsSpan(), format.ToUpperInvariant(), out result));
+ Assert.Equal(expected, result);
+
+ Assert.True(Guid.TryParseExact(input.AsSpan(), format.ToLowerInvariant(), out result)); // Format should be case insensitive
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(GuidStrings_Invalid_TestData))]
+ public static void Parse_Span_InvalidInput_Fails(string input, Type exceptionType)
+ {
+ if (input == null)
+ {
+ return;
+ }
+
+ // Overflow exceptions throw as format exceptions in Parse
+ if (exceptionType.Equals(typeof(OverflowException)))
+ {
+ exceptionType = typeof(FormatException);
+ }
+ Assert.Throws(exceptionType, () => Guid.Parse(input.AsSpan()));
+
+ Assert.False(Guid.TryParse(input.AsSpan(), out Guid result));
+ Assert.Equal(Guid.Empty, result);
+
+ foreach (string format in new[] { "N", "D", "B", "P", "X" })
+ {
+ Assert.Throws(exceptionType, () => Guid.ParseExact(input.AsSpan(), format));
+
+ Assert.False(Guid.TryParseExact(input.AsSpan(), format, out result));
+ Assert.Equal(Guid.Empty, result);
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Xunit;
-
-namespace System.Tests
-{
- public static partial class GuidTests
- {
- [Theory]
- [MemberData(nameof(Ctor_ByteArray_TestData))]
- public static void Ctor_ReadOnlySpan(byte[] b, Guid expected)
- {
- Assert.Equal(expected, new Guid(new ReadOnlySpan<byte>(b)));
- }
-
- [Theory]
- [InlineData(15)]
- [InlineData(17)]
- public static void CtorSpan_InvalidLengthByteArray_ThrowsArgumentException(int length)
- {
- AssertExtensions.Throws<ArgumentException>("b", null, () => new Guid(new ReadOnlySpan<byte>(new byte[length])));
- }
-
- [Theory]
- [MemberData(nameof(Ctor_ByteArray_TestData))]
- public static void TryWriteBytes_ValidLength_ReturnsTrue(byte[] b, Guid guid)
- {
- var bytes = new byte[16];
- Assert.True(guid.TryWriteBytes(new Span<byte>(bytes)));
- Assert.Equal(b, bytes);
- }
-
- [Theory]
- [InlineData(0)]
- [InlineData(15)]
- public static void TryWriteBytes_LengthTooShort_ReturnsFalse(int length)
- {
- Assert.False(s_testGuid.TryWriteBytes(new Span<byte>(new byte[length])));
- }
-
- [Theory]
- [MemberData(nameof(InvalidFormat_TestData))]
- public static void TryFormat_InvalidFormat_ThrowsFormatException(string format)
- {
- Assert.Throws<FormatException>(() => s_testGuid.TryFormat(new Span<char>(), out int charsWritten, format));
- Assert.Throws<FormatException>(() => s_testGuid.TryFormat(new Span<char>(), out int charsWritten, format.ToUpperInvariant()));
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat_LengthTooSmall_ReturnsFalse(Guid guid, string format, string expected)
- {
- _ = expected;
- Assert.False(guid.TryFormat(new Span<char>(new char[guid.ToString(format).Length - 1]), out int charsWritten, format));
- Assert.Equal(0, charsWritten);
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat_CharsWritten_EqualsZero_WhenSpanTooSmall(Guid guid, string format, string expected)
- {
- _ = expected;
- Assert.False(guid.TryFormat(new Span<char>(new char[guid.ToString(format).Length - 1]), out int charsWritten, format));
- Assert.Equal(0, charsWritten);
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat_ValidLength_ReturnsTrue(Guid guid, string format, string expected)
- {
- char[] chars = new char[guid.ToString(format).Length];
- Assert.True(guid.TryFormat(new Span<char>(chars), out int charsWritten, format));
- Assert.Equal(chars, expected.ToCharArray());
- }
-
- [Theory]
- [MemberData(nameof(GuidStrings_Valid_TestData))]
- public static void Parse_Span_ValidInput_Success(string input, string format, Guid expected)
- {
- Assert.Equal(expected, Guid.Parse(input.AsSpan()));
- Assert.Equal(expected, Guid.ParseExact(input.AsSpan(), format.ToUpperInvariant()));
- Assert.Equal(expected, Guid.ParseExact(input.AsSpan(), format.ToLowerInvariant())); // Format should be case insensitive
-
- Guid result;
-
- Assert.True(Guid.TryParse(input.AsSpan(), out result));
- Assert.Equal(expected, result);
-
- Assert.True(Guid.TryParseExact(input.AsSpan(), format.ToUpperInvariant(), out result));
- Assert.Equal(expected, result);
-
- Assert.True(Guid.TryParseExact(input.AsSpan(), format.ToLowerInvariant(), out result)); // Format should be case insensitive
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(GuidStrings_Invalid_TestData))]
- public static void Parse_Span_InvalidInput_Fails(string input, Type exceptionType)
- {
- if (input == null)
- {
- return;
- }
-
- // Overflow exceptions throw as format exceptions in Parse
- if (exceptionType.Equals(typeof(OverflowException)))
- {
- exceptionType = typeof(FormatException);
- }
- Assert.Throws(exceptionType, () => Guid.Parse(input.AsSpan()));
-
- Assert.False(Guid.TryParse(input.AsSpan(), out Guid result));
- Assert.Equal(Guid.Empty, result);
-
- foreach (string format in new[] { "N", "D", "B", "P", "X" })
- {
- Assert.Throws(exceptionType, () => Guid.ParseExact(input.AsSpan(), format));
-
- Assert.False(Guid.TryParseExact(input.AsSpan(), format, out result));
- Assert.Equal(Guid.Empty, result);
- }
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+public static class HashCodeTests
+{
+ [Fact]
+ public static void HashCode_Add()
+ {
+ // The version of xUnit used by corefx does not support params theories.
+ void Theory(uint expected, params uint[] vector)
+ {
+ var hc = new HashCode();
+ for (int i = 0; i < vector.Length; i++)
+ hc.Add(vector[i]);
+
+#if SYSTEM_HASHCODE_TESTVECTORS
+ // HashCode is not deterministic across AppDomains by design. This means
+ // that these tests can not be executed against the version that exists
+ // within CoreCLR. Copy HashCode and set m_seed to 0 in order to execute
+ // these tests.
+
+ Assert.Equal(expected, (uint)hc.ToHashCode());
+#else
+ // Validate that the HashCode.m_seed is randomized. This has a 1 in 4
+ // billion chance of resulting in a false negative, as HashCode.m_seed
+ // can be 0.
+
+ Assert.NotEqual(expected, (uint)hc.ToHashCode());
+#endif
+ }
+
+ // These test vectors were created using https://asecuritysite.com/encryption/xxHash
+ // 1. Find the hash for "".
+ // 2. Find the hash for "abcd". ASCII "abcd" and bit convert to uint.
+ // 3. Find the hash for "abcd1234". ASCII [ "abcd", "1234"] and bit convert to 2 uints.
+ // n. Continue until "abcd0123efgh4567ijkl8901mnop2345qrst6789uvwx0123yzab".
+
+ Theory(0x02cc5d05U);
+ Theory(0xa3643705U, 0x64636261U );
+ Theory(0x4603e94cU, 0x64636261U, 0x33323130U );
+ Theory(0xd8a1e80fU, 0x64636261U, 0x33323130U, 0x68676665U );
+ Theory(0x4b62a7cfU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U );
+ Theory(0xc33a7641U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U );
+ Theory(0x1a794705U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U );
+ Theory(0x4d79177dU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU );
+ Theory(0x59d79205U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U );
+ Theory(0x49585aaeU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U );
+ Theory(0x2f005ff1U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U );
+ Theory(0x0ce339bdU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U, 0x78777675U );
+ Theory(0xb31bd2ffU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U, 0x78777675U, 0x33323130U );
+ Theory(0xa821efa3U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U, 0x78777675U, 0x33323130U, 0x62617a79U );
+ }
+
+ [Fact]
+ public static void HashCode_Add_HashCode()
+ {
+ var hc1 = new HashCode();
+ hc1.Add("Hello");
+
+ var hc2 = new HashCode();
+ hc2.Add("Hello".GetHashCode());
+
+ Assert.Equal(hc1.ToHashCode(), hc2.ToHashCode());
+ }
+
+ [Fact]
+ public static void HashCode_Add_Generic()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(new ConstHashCodeType());
+
+ var expected = new HashCode();
+ expected.Add(1);
+ expected.Add(ConstComparer.ConstantValue);
+
+ Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
+ }
+
+ [Fact]
+ public static void HashCode_Add_Null()
+ {
+ var hc = new HashCode();
+ hc.Add<string>(null);
+
+ var expected = new HashCode();
+ expected.Add(EqualityComparer<string>.Default.GetHashCode(null));
+
+ Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
+ }
+
+ [Fact]
+ public static void HashCode_Add_GenericEqualityComparer()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add("Hello", new ConstComparer());
+
+ var expected = new HashCode();
+ expected.Add(1);
+ expected.Add(ConstComparer.ConstantValue);
+
+ Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
+ }
+
+ [Fact]
+ public static void HashCode_Add_NullEqualityComparer()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add("Hello", null);
+
+ var expected = new HashCode();
+ expected.Add(1);
+ expected.Add("Hello");
+
+ Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
+ }
+
+ [Fact]
+ public static void HashCode_Combine()
+ {
+ var hcs = new int[]
+ {
+ HashCode.Combine(1),
+ HashCode.Combine(1, 2),
+ HashCode.Combine(1, 2, 3),
+ HashCode.Combine(1, 2, 3, 4),
+ HashCode.Combine(1, 2, 3, 4, 5),
+ HashCode.Combine(1, 2, 3, 4, 5, 6),
+ HashCode.Combine(1, 2, 3, 4, 5, 6, 7),
+ HashCode.Combine(1, 2, 3, 4, 5, 6, 7, 8),
+
+ HashCode.Combine(2),
+ HashCode.Combine(2, 3),
+ HashCode.Combine(2, 3, 4),
+ HashCode.Combine(2, 3, 4, 5),
+ HashCode.Combine(2, 3, 4, 5, 6),
+ HashCode.Combine(2, 3, 4, 5, 6, 7),
+ HashCode.Combine(2, 3, 4, 5, 6, 7, 8),
+ HashCode.Combine(2, 3, 4, 5, 6, 7, 8, 9),
+ };
+
+ for (int i = 0; i < hcs.Length; i++)
+ for (int j = 0; j < hcs.Length; j++)
+ {
+ if (i == j) continue;
+ Assert.NotEqual(hcs[i], hcs[j]);
+ }
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_1()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1));
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_2()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(2);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2));
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_3()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(2);
+ hc.Add(3);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3));
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_4()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(2);
+ hc.Add(3);
+ hc.Add(4);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4));
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_5()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(2);
+ hc.Add(3);
+ hc.Add(4);
+ hc.Add(5);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5));
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_6()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(2);
+ hc.Add(3);
+ hc.Add(4);
+ hc.Add(5);
+ hc.Add(6);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5, 6));
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_7()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(2);
+ hc.Add(3);
+ hc.Add(4);
+ hc.Add(5);
+ hc.Add(6);
+ hc.Add(7);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5, 6, 7));
+ }
+
+ [Fact]
+ public static void HashCode_Combine_Add_8()
+ {
+ var hc = new HashCode();
+ hc.Add(1);
+ hc.Add(2);
+ hc.Add(3);
+ hc.Add(4);
+ hc.Add(5);
+ hc.Add(6);
+ hc.Add(7);
+ hc.Add(8);
+ Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5, 6, 7, 8));
+ }
+
+ [Fact]
+ public static void HashCode_GetHashCode()
+ {
+ var hc = new HashCode();
+
+ Assert.Throws<NotSupportedException>(() => hc.GetHashCode());
+ }
+
+ [Fact]
+ public static void HashCode_Equals()
+ {
+ var hc = new HashCode();
+
+ Assert.Throws<NotSupportedException>(() => hc.Equals(hc));
+ }
+
+ [Fact]
+ public static void HashCode_GetHashCode_Boxed()
+ {
+ var hc = new HashCode();
+ var obj = (object)hc;
+
+ Assert.Throws<NotSupportedException>(() => obj.GetHashCode());
+ }
+
+ [Fact]
+ public static void HashCode_Equals_Boxed()
+ {
+ var hc = new HashCode();
+ var obj = (object)hc;
+
+ Assert.Throws<NotSupportedException>(() => obj.Equals(obj));
+ }
+
+ public class ConstComparer : System.Collections.Generic.IEqualityComparer<string>
+ {
+ public const int ConstantValue = 1234;
+
+ public bool Equals(string x, string y) => false;
+ public int GetHashCode(string obj) => ConstantValue;
+ }
+
+ public class ConstHashCodeType
+ {
+ public override int GetHashCode() => ConstComparer.ConstantValue;
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using Xunit;
-
-public static class HashCodeTests
-{
- [Fact]
- public static void HashCode_Add()
- {
- // The version of xUnit used by corefx does not support params theories.
- void Theory(uint expected, params uint[] vector)
- {
- var hc = new HashCode();
- for (int i = 0; i < vector.Length; i++)
- hc.Add(vector[i]);
-
-#if SYSTEM_HASHCODE_TESTVECTORS
- // HashCode is not deterministic across AppDomains by design. This means
- // that these tests can not be executed against the version that exists
- // within CoreCLR. Copy HashCode and set m_seed to 0 in order to execute
- // these tests.
-
- Assert.Equal(expected, (uint)hc.ToHashCode());
-#else
- // Validate that the HashCode.m_seed is randomized. This has a 1 in 4
- // billion chance of resulting in a false negative, as HashCode.m_seed
- // can be 0.
-
- Assert.NotEqual(expected, (uint)hc.ToHashCode());
-#endif
- }
-
- // These test vectors were created using https://asecuritysite.com/encryption/xxHash
- // 1. Find the hash for "".
- // 2. Find the hash for "abcd". ASCII "abcd" and bit convert to uint.
- // 3. Find the hash for "abcd1234". ASCII [ "abcd", "1234"] and bit convert to 2 uints.
- // n. Continue until "abcd0123efgh4567ijkl8901mnop2345qrst6789uvwx0123yzab".
-
- Theory(0x02cc5d05U);
- Theory(0xa3643705U, 0x64636261U );
- Theory(0x4603e94cU, 0x64636261U, 0x33323130U );
- Theory(0xd8a1e80fU, 0x64636261U, 0x33323130U, 0x68676665U );
- Theory(0x4b62a7cfU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U );
- Theory(0xc33a7641U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U );
- Theory(0x1a794705U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U );
- Theory(0x4d79177dU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU );
- Theory(0x59d79205U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U );
- Theory(0x49585aaeU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U );
- Theory(0x2f005ff1U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U );
- Theory(0x0ce339bdU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U, 0x78777675U );
- Theory(0xb31bd2ffU, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U, 0x78777675U, 0x33323130U );
- Theory(0xa821efa3U, 0x64636261U, 0x33323130U, 0x68676665U, 0x37363534U, 0x6c6b6a69U, 0x31303938U, 0x706f6e6dU, 0x35343332U, 0x74737271U, 0x39383736U, 0x78777675U, 0x33323130U, 0x62617a79U );
- }
-
- [Fact]
- public static void HashCode_Add_HashCode()
- {
- var hc1 = new HashCode();
- hc1.Add("Hello");
-
- var hc2 = new HashCode();
- hc2.Add("Hello".GetHashCode());
-
- Assert.Equal(hc1.ToHashCode(), hc2.ToHashCode());
- }
-
- [Fact]
- public static void HashCode_Add_Generic()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(new ConstHashCodeType());
-
- var expected = new HashCode();
- expected.Add(1);
- expected.Add(ConstComparer.ConstantValue);
-
- Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
- }
-
- [Fact]
- public static void HashCode_Add_Null()
- {
- var hc = new HashCode();
- hc.Add<string>(null);
-
- var expected = new HashCode();
- expected.Add(EqualityComparer<string>.Default.GetHashCode(null));
-
- Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
- }
-
- [Fact]
- public static void HashCode_Add_GenericEqualityComparer()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add("Hello", new ConstComparer());
-
- var expected = new HashCode();
- expected.Add(1);
- expected.Add(ConstComparer.ConstantValue);
-
- Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
- }
-
- [Fact]
- public static void HashCode_Add_NullEqualityComparer()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add("Hello", null);
-
- var expected = new HashCode();
- expected.Add(1);
- expected.Add("Hello");
-
- Assert.Equal(expected.ToHashCode(), hc.ToHashCode());
- }
-
- [Fact]
- public static void HashCode_Combine()
- {
- var hcs = new int[]
- {
- HashCode.Combine(1),
- HashCode.Combine(1, 2),
- HashCode.Combine(1, 2, 3),
- HashCode.Combine(1, 2, 3, 4),
- HashCode.Combine(1, 2, 3, 4, 5),
- HashCode.Combine(1, 2, 3, 4, 5, 6),
- HashCode.Combine(1, 2, 3, 4, 5, 6, 7),
- HashCode.Combine(1, 2, 3, 4, 5, 6, 7, 8),
-
- HashCode.Combine(2),
- HashCode.Combine(2, 3),
- HashCode.Combine(2, 3, 4),
- HashCode.Combine(2, 3, 4, 5),
- HashCode.Combine(2, 3, 4, 5, 6),
- HashCode.Combine(2, 3, 4, 5, 6, 7),
- HashCode.Combine(2, 3, 4, 5, 6, 7, 8),
- HashCode.Combine(2, 3, 4, 5, 6, 7, 8, 9),
- };
-
- for (int i = 0; i < hcs.Length; i++)
- for (int j = 0; j < hcs.Length; j++)
- {
- if (i == j) continue;
- Assert.NotEqual(hcs[i], hcs[j]);
- }
- }
-
- [Fact]
- public static void HashCode_Combine_Add_1()
- {
- var hc = new HashCode();
- hc.Add(1);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1));
- }
-
- [Fact]
- public static void HashCode_Combine_Add_2()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(2);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2));
- }
-
- [Fact]
- public static void HashCode_Combine_Add_3()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(2);
- hc.Add(3);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3));
- }
-
- [Fact]
- public static void HashCode_Combine_Add_4()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(2);
- hc.Add(3);
- hc.Add(4);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4));
- }
-
- [Fact]
- public static void HashCode_Combine_Add_5()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(2);
- hc.Add(3);
- hc.Add(4);
- hc.Add(5);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5));
- }
-
- [Fact]
- public static void HashCode_Combine_Add_6()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(2);
- hc.Add(3);
- hc.Add(4);
- hc.Add(5);
- hc.Add(6);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5, 6));
- }
-
- [Fact]
- public static void HashCode_Combine_Add_7()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(2);
- hc.Add(3);
- hc.Add(4);
- hc.Add(5);
- hc.Add(6);
- hc.Add(7);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5, 6, 7));
- }
-
- [Fact]
- public static void HashCode_Combine_Add_8()
- {
- var hc = new HashCode();
- hc.Add(1);
- hc.Add(2);
- hc.Add(3);
- hc.Add(4);
- hc.Add(5);
- hc.Add(6);
- hc.Add(7);
- hc.Add(8);
- Assert.Equal(hc.ToHashCode(), HashCode.Combine(1, 2, 3, 4, 5, 6, 7, 8));
- }
-
- [Fact]
- public static void HashCode_GetHashCode()
- {
- var hc = new HashCode();
-
- Assert.Throws<NotSupportedException>(() => hc.GetHashCode());
- }
-
- [Fact]
- public static void HashCode_Equals()
- {
- var hc = new HashCode();
-
- Assert.Throws<NotSupportedException>(() => hc.Equals(hc));
- }
-
- [Fact]
- public static void HashCode_GetHashCode_Boxed()
- {
- var hc = new HashCode();
- var obj = (object)hc;
-
- Assert.Throws<NotSupportedException>(() => obj.GetHashCode());
- }
-
- [Fact]
- public static void HashCode_Equals_Boxed()
- {
- var hc = new HashCode();
- var obj = (object)hc;
-
- Assert.Throws<NotSupportedException>(() => obj.Equals(obj));
- }
-
- public class ConstComparer : System.Collections.Generic.IEqualityComparer<string>
- {
- public const int ConstantValue = 1234;
-
- public bool Equals(string x, string y) => false;
- public int GetHashCode(string obj) => ConstantValue;
- }
-
- public class ConstHashCodeType
- {
- public override int GetHashCode() => ConstComparer.ConstantValue;
- }
-}
namespace System.Tests
{
- public partial class Int16Tests
+ public class Int16Tests
{
[Fact]
public static void Ctor_Empty()
AssertExtensions.Throws<ArgumentException>(paramName, () => short.Parse("1", style));
AssertExtensions.Throws<ArgumentException>(paramName, () => short.Parse("1", style, null));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "-32767", 1, 5, NumberStyles.Integer, null, (short)32767 };
+ yield return new object[] { "-32768", 0, 5, NumberStyles.Integer, null, (short)-3276 };
+ yield return new object[] { "abc", 0, 2, NumberStyles.HexNumber, null, (short)0xab };
+ yield return new object[] { "abc", 1, 2, NumberStyles.HexNumber, null, (short)0xbc };
+ yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, null, (short)123 };
+ yield return new object[] { "123", 0, 1, NumberStyles.Integer, new NumberFormatInfo(), (short)1 };
+ yield return new object[] { "$1,000", 1, 5, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (short)1000 };
+ yield return new object[] { "$1,000", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (short)1 };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, short expected)
+ {
+ short result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(short.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, short.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(short.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ short result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(short.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0, result);
+ }
+
+ Assert.Throws(exceptionType, () => short.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(short.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(short i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class Int16Tests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "-32767", 1, 5, NumberStyles.Integer, null, (short)32767 };
- yield return new object[] { "-32768", 0, 5, NumberStyles.Integer, null, (short)-3276 };
- yield return new object[] { "abc", 0, 2, NumberStyles.HexNumber, null, (short)0xab };
- yield return new object[] { "abc", 1, 2, NumberStyles.HexNumber, null, (short)0xbc };
- yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, null, (short)123 };
- yield return new object[] { "123", 0, 1, NumberStyles.Integer, new NumberFormatInfo(), (short)1 };
- yield return new object[] { "$1,000", 1, 5, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (short)1000 };
- yield return new object[] { "$1,000", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (short)1 };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, short expected)
- {
- short result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(short.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, short.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(short.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- short result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(short.TryParse(value.AsSpan(), out result));
- Assert.Equal(0, result);
- }
-
- Assert.Throws(exceptionType, () => short.Parse(value.AsSpan(), style, provider));
-
- Assert.False(short.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(short i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
namespace System.Tests
{
- public partial class Int32Tests
+ public class Int32Tests
{
[Fact]
public static void Ctor_Empty()
nfi.CurrencySymbol = "$";
Assert.Equal("$1234", 1234.ToString("C0", nfi));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ NumberFormatInfo samePositiveNegativeFormat = new NumberFormatInfo()
+ {
+ PositiveSign = "|",
+ NegativeSign = "|"
+ };
+
+ NumberFormatInfo emptyPositiveFormat = new NumberFormatInfo() { PositiveSign = "" };
+ NumberFormatInfo emptyNegativeFormat = new NumberFormatInfo() { NegativeSign = "" };
+
+ // None
+ yield return new object[] { "2147483647", 1, 9, NumberStyles.None, null, 147483647 };
+ yield return new object[] { "2147483647", 1, 1, NumberStyles.None, null, 1 };
+ yield return new object[] { "123\0\0", 2, 2, NumberStyles.None, null, 3 };
+
+ // Hex
+ yield return new object[] { "abc", 0, 1, NumberStyles.HexNumber, null, 0xa };
+ yield return new object[] { "ABC", 1, 1, NumberStyles.HexNumber, null, 0xB };
+ yield return new object[] { "FFFFFFFF", 6, 2, NumberStyles.HexNumber, null, 0xFF };
+ yield return new object[] { "FFFFFFFF", 0, 1, NumberStyles.HexNumber, null, 0xF };
+
+ // Currency
+ yield return new object[] { "-$1000", 1, 5, NumberStyles.Currency, new NumberFormatInfo()
+ {
+ CurrencySymbol = "$",
+ CurrencyGroupSeparator = "|",
+ NumberGroupSeparator = "/"
+ }, 1000 };
+
+ NumberFormatInfo emptyCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "" };
+ yield return new object[] { "100", 1, 2, NumberStyles.Currency, emptyCurrencyFormat, 0 };
+ yield return new object[] { "100", 0, 1, NumberStyles.Currency, emptyCurrencyFormat, 1 };
+
+ // If CurrencySymbol and Negative are the same, NegativeSign is preferred
+ NumberFormatInfo sameCurrencyNegativeSignFormat = new NumberFormatInfo()
+ {
+ NegativeSign = "|",
+ CurrencySymbol = "|"
+ };
+ yield return new object[] { "1000", 1, 3, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, 0 };
+ yield return new object[] { "|1000", 0, 2, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, -1 };
+
+ // Any
+ yield return new object[] { "123", 0, 2, NumberStyles.Any, null, 12 };
+
+ // AllowLeadingSign
+ yield return new object[] { "-2147483648", 0, 10, NumberStyles.AllowLeadingSign, null, -214748364 };
+
+ // AllowTrailingSign
+ yield return new object[] { "123-", 0, 3, NumberStyles.AllowTrailingSign, null, 123 };
+
+ // AllowExponent
+ yield return new object[] { "1E2", 0, 1, NumberStyles.AllowExponent, null, 1 };
+ yield return new object[] { "1E+2", 3, 1, NumberStyles.AllowExponent, null, 2 };
+ yield return new object[] { "(1E2)", 1, 3, NumberStyles.AllowExponent | NumberStyles.AllowParentheses, null, 1E2 };
+ yield return new object[] { "-1E2", 1, 3, NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, null, 1E2 };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, int expected)
+ {
+ int result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(int.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, int.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(int.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ int result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(int.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0, result);
+ }
+
+ Assert.Throws(exceptionType, () => int.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(int.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(int i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class Int32Tests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- NumberFormatInfo samePositiveNegativeFormat = new NumberFormatInfo()
- {
- PositiveSign = "|",
- NegativeSign = "|"
- };
-
- NumberFormatInfo emptyPositiveFormat = new NumberFormatInfo() { PositiveSign = "" };
- NumberFormatInfo emptyNegativeFormat = new NumberFormatInfo() { NegativeSign = "" };
-
- // None
- yield return new object[] { "2147483647", 1, 9, NumberStyles.None, null, 147483647 };
- yield return new object[] { "2147483647", 1, 1, NumberStyles.None, null, 1 };
- yield return new object[] { "123\0\0", 2, 2, NumberStyles.None, null, 3 };
-
- // Hex
- yield return new object[] { "abc", 0, 1, NumberStyles.HexNumber, null, 0xa };
- yield return new object[] { "ABC", 1, 1, NumberStyles.HexNumber, null, 0xB };
- yield return new object[] { "FFFFFFFF", 6, 2, NumberStyles.HexNumber, null, 0xFF };
- yield return new object[] { "FFFFFFFF", 0, 1, NumberStyles.HexNumber, null, 0xF };
-
- // Currency
- yield return new object[] { "-$1000", 1, 5, NumberStyles.Currency, new NumberFormatInfo()
- {
- CurrencySymbol = "$",
- CurrencyGroupSeparator = "|",
- NumberGroupSeparator = "/"
- }, 1000 };
-
- NumberFormatInfo emptyCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "" };
- yield return new object[] { "100", 1, 2, NumberStyles.Currency, emptyCurrencyFormat, 0 };
- yield return new object[] { "100", 0, 1, NumberStyles.Currency, emptyCurrencyFormat, 1 };
-
- // If CurrencySymbol and Negative are the same, NegativeSign is preferred
- NumberFormatInfo sameCurrencyNegativeSignFormat = new NumberFormatInfo()
- {
- NegativeSign = "|",
- CurrencySymbol = "|"
- };
- yield return new object[] { "1000", 1, 3, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, 0 };
- yield return new object[] { "|1000", 0, 2, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, -1 };
-
- // Any
- yield return new object[] { "123", 0, 2, NumberStyles.Any, null, 12 };
-
- // AllowLeadingSign
- yield return new object[] { "-2147483648", 0, 10, NumberStyles.AllowLeadingSign, null, -214748364 };
-
- // AllowTrailingSign
- yield return new object[] { "123-", 0, 3, NumberStyles.AllowTrailingSign, null, 123 };
-
- // AllowExponent
- yield return new object[] { "1E2", 0, 1, NumberStyles.AllowExponent, null, 1 };
- yield return new object[] { "1E+2", 3, 1, NumberStyles.AllowExponent, null, 2 };
- yield return new object[] { "(1E2)", 1, 3, NumberStyles.AllowExponent | NumberStyles.AllowParentheses, null, 1E2 };
- yield return new object[] { "-1E2", 1, 3, NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, null, 1E2 };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, int expected)
- {
- int result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(int.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, int.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(int.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- int result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(int.TryParse(value.AsSpan(), out result));
- Assert.Equal(0, result);
- }
-
- Assert.Throws(exceptionType, () => int.Parse(value.AsSpan(), style, provider));
-
- Assert.False(int.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(int i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
namespace System.Tests
{
- public partial class Int64Tests
+ public class Int64Tests
{
[Fact]
public static void Ctor_Empty()
AssertExtensions.Throws<ArgumentException>(paramName, () => long.Parse("1", style));
AssertExtensions.Throws<ArgumentException>(paramName, () => long.Parse("1", style, null));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "-9223372036854775808", 0, 19, NumberStyles.Integer, null, -922337203685477580 };
+ yield return new object[] { "09223372036854775807", 1, 19, NumberStyles.Integer, null, 9223372036854775807 };
+ yield return new object[] { "9223372036854775807", 0, 1, NumberStyles.Integer, null, 9 };
+ yield return new object[] { "ABC", 0, 2, NumberStyles.HexNumber, null, (long)0xAB };
+ yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, null, (long)123 };
+ yield return new object[] { "$1,000", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (long)1 };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, long expected)
+ {
+ long result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(long.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, long.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(long.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ long result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(long.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0, result);
+ }
+
+ Assert.Throws(exceptionType, () => long.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(long.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(long i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class Int64Tests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "-9223372036854775808", 0, 19, NumberStyles.Integer, null, -922337203685477580 };
- yield return new object[] { "09223372036854775807", 1, 19, NumberStyles.Integer, null, 9223372036854775807 };
- yield return new object[] { "9223372036854775807", 0, 1, NumberStyles.Integer, null, 9 };
- yield return new object[] { "ABC", 0, 2, NumberStyles.HexNumber, null, (long)0xAB };
- yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, null, (long)123 };
- yield return new object[] { "$1,000", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (long)1 };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, long expected)
- {
- long result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(long.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, long.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(long.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- long result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(long.TryParse(value.AsSpan(), out result));
- Assert.Equal(0, result);
- }
-
- Assert.Throws(exceptionType, () => long.Parse(value.AsSpan(), style, provider));
-
- Assert.False(long.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(long i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
namespace System.Tests
{
- public static partial class IntPtrTests
+ public static class IntPtrTests
{
private static unsafe bool Is64Bit => sizeof(void*) == 8;
Assert.Equal(expected, ptr1 == ptr2);
Assert.Equal(!expected, ptr1 != ptr2);
Assert.Equal(expected, ptr1.GetHashCode().Equals(ptr2.GetHashCode()));
+
+ IEquatable<IntPtr> iEquatable = ptr1;
+ Assert.Equal(expected, iEquatable.Equals((IntPtr)obj));
}
Assert.Equal(expected, ptr1.Equals(obj));
Assert.Equal(ptr1.GetHashCode(), ptr1.GetHashCode());
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using Xunit;
-
-namespace System.Tests
-{
- public static partial class IntPtrTests
- {
- [Theory]
- [MemberData(nameof(Equals_TestData))]
- public static void Equals_NetCoreApp11(IntPtr ptr, object obj, bool expected)
- {
- if (!(obj is IntPtr))
- {
- return;
- }
-
- IEquatable<IntPtr> iEquatable = ptr;
- Assert.Equal(expected, iEquatable.Equals((IntPtr)obj));
- }
- }
-}
namespace System.Tests
{
- public static partial class LazyTests
+ public static class LazyTests
{
[Fact]
public static void Ctor()
Assert.Equal(template, d);
}
+ [Fact]
+ public static void Ctor_Value_ReferenceType()
+ {
+ var lazyString = new Lazy<string>("abc");
+ VerifyLazy(lazyString, "abc", hasValue: true, isValueCreated: true);
+ }
+
+ [Fact]
+ public static void Ctor_Value_ValueType()
+ {
+ var lazyObject = new Lazy<int>(123);
+ VerifyLazy(lazyObject, 123, hasValue: true, isValueCreated: true);
+ }
+
+ [Fact]
+ public static void EnsureInitialized_FuncInitializationWithoutTrackingBool_Uninitialized()
+ {
+ string template = "foo";
+ string target = null;
+ object syncLock = null;
+ Assert.Equal(template, LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => template));
+ Assert.Equal(template, target);
+ Assert.NotNull(syncLock);
+ }
+
+ [Fact]
+ public static void EnsureInitialized_FuncInitializationWithoutTrackingBool_Initialized()
+ {
+ string template = "foo";
+ string target = template;
+ object syncLock = null;
+ Assert.Equal(template, LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => template + "bar"));
+ Assert.Equal(template, target);
+ Assert.Null(syncLock);
+ }
+
+ [Fact]
+ public static void EnsureInitializer_FuncInitializationWithoutTrackingBool_Null()
+ {
+ string target = null;
+ object syncLock = null;
+ Assert.Throws<InvalidOperationException>(() => LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => null));
+ }
private static void VerifyLazy<T>(Lazy<T> lazy, T expectedValue, bool hasValue, bool isValueCreated)
{
Assert.Equal(isValueCreated, lazy.IsValueCreated);
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading;
-using Xunit;
-
-namespace System.Tests
-{
- public static partial class LazyTests
- {
- [Fact]
- public static void Ctor_Value_ReferenceType()
- {
- var lazyString = new Lazy<string>("abc");
- VerifyLazy(lazyString, "abc", hasValue: true, isValueCreated: true);
- }
-
- [Fact]
- public static void Ctor_Value_ValueType()
- {
- var lazyObject = new Lazy<int>(123);
- VerifyLazy(lazyObject, 123, hasValue: true, isValueCreated: true);
- }
-
- [Fact]
- public static void EnsureInitialized_FuncInitializationWithoutTrackingBool_Uninitialized()
- {
- string template = "foo";
- string target = null;
- object syncLock = null;
- Assert.Equal(template, LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => template));
- Assert.Equal(template, target);
- Assert.NotNull(syncLock);
- }
-
- [Fact]
- public static void EnsureInitialized_FuncInitializationWithoutTrackingBool_Initialized()
- {
- string template = "foo";
- string target = template;
- object syncLock = null;
- Assert.Equal(template, LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => template + "bar"));
- Assert.Equal(template, target);
- Assert.Null(syncLock);
- }
-
- [Fact]
- public static void EnsureInitializer_FuncInitializationWithoutTrackingBool_Null()
- {
- string target = null;
- object syncLock = null;
- Assert.Throws<InvalidOperationException>(() => LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => null));
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using Xunit;
+
+namespace System.Tests
+{
+ public class RealFormatterTests : RealFormatterTestsBase
+ {
+ // The actual tests are defined in: src\Common\tests\System\RealFormatterTestsBase.netcoreapp.cs
+
+ protected override string InvariantToStringDouble(double d, string format)
+ {
+ return d.ToString(format, CultureInfo.InvariantCulture);
+ }
+
+ protected override string InvariantToStringSingle(float f, string format)
+ {
+ return f.ToString(format, CultureInfo.InvariantCulture);
+ }
+
+ [Theory]
+ [InlineData("##.#", double.Epsilon, "")]
+ [InlineData("##.#", double.MaxValue, "179769313486232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
+ [InlineData("##.#", Math.E, "2.7")]
+ [InlineData("##.#", Math.PI, "3.1")]
+ [InlineData("##.#", 0.0, "")]
+ [InlineData("##.#", 0.0046, "")]
+ [InlineData("##.#", 0.005, "")]
+ [InlineData("##.#", 0.125, ".1")]
+ [InlineData("##.#", 0.5, ".5")]
+ [InlineData("##.#", 0.51, ".5")]
+ [InlineData("##.#", 0.56789, ".6")]
+ [InlineData("##.#", 0.84551240822557006, ".8")]
+ [InlineData("##.#", 1.0, "1")]
+ [InlineData("##.#", 46.5f, "46.5")]
+ [InlineData("##.#", 505.0, "505")]
+ [InlineData("##.#", 506.0, "506")]
+ [InlineData("##.#", 545.0, "545")]
+ [InlineData("##.#", 545.1, "545.1")]
+ [InlineData("##.#", 555.0, "555")]
+ [InlineData("##.#", 46500.0f, "46500")]
+ [InlineData("##.#", 65747.125, "65747.1")]
+ [InlineData("##.#", 1844674407370955.25, "1844674407370960")]
+ [InlineData("#,###.00", double.Epsilon, ".00")]
+ [InlineData("#,###.00", double.MaxValue, "179,769,313,486,232,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.00")]
+ [InlineData("#,###.00", Math.E, "2.72")]
+ [InlineData("#,###.00", Math.PI, "3.14")]
+ [InlineData("#,###.00", 0.0, ".00")]
+ [InlineData("#,###.00", 0.0046, ".00")]
+ [InlineData("#,###.00", 0.005, ".01")]
+ [InlineData("#,###.00", 0.125, ".13")]
+ [InlineData("#,###.00", 0.5, ".50")]
+ [InlineData("#,###.00", 0.51, ".51")]
+ [InlineData("#,###.00", 0.56789, ".57")]
+ [InlineData("#,###.00", 0.84551240822557006, ".85")]
+ [InlineData("#,###.00", 1.0, "1.00")]
+ [InlineData("#,###.00", 46.5f, "46.50")]
+ [InlineData("#,###.00", 505.0, "505.00")]
+ [InlineData("#,###.00", 506.0, "506.00")]
+ [InlineData("#,###.00", 545.0, "545.00")]
+ [InlineData("#,###.00", 545.1, "545.10")]
+ [InlineData("#,###.00", 555.0, "555.00")]
+ [InlineData("#,###.00", 46500.0f, "46,500.00")]
+ [InlineData("#,###.00", 65747.125, "65,747.13")]
+ [InlineData("#,###.00", 1844674407370955.25, "1,844,674,407,370,960.00")]
+ public void TestFormatterDouble_Custom(string format, double value, string expectedResult) => TestFormatterDouble_Standard(value, format, expectedResult);
+
+ [Theory]
+ [InlineData("##.#", float.Epsilon, "")]
+ [InlineData("##.#", float.MaxValue, "340282300000000000000000000000000000000")]
+ [InlineData("##.#", MathF.E, "2.7")]
+ [InlineData("##.#", MathF.PI, "3.1")]
+ [InlineData("##.#", 0.0f, "")]
+ [InlineData("##.#", 0.0046f, "")]
+ [InlineData("##.#", 0.005f, "")]
+ [InlineData("##.#", 0.125f, ".1")]
+ [InlineData("##.#", 0.5f, ".5")]
+ [InlineData("##.#", 0.51f, ".5")]
+ [InlineData("##.#", 0.56789f, ".6")]
+ [InlineData("##.#", 0.845512390f, ".8")]
+ [InlineData("##.#", 1.0f, "1")]
+ [InlineData("##.#", 46.5f, "46.5")]
+ [InlineData("##.#", 505.0f, "505")]
+ [InlineData("##.#", 506.0f, "506")]
+ [InlineData("##.#", 545.0f, "545")]
+ [InlineData("##.#", 545.1f, "545.1")]
+ [InlineData("##.#", 555.0f, "555")]
+ [InlineData("##.#", 46500.0f, "46500")]
+ [InlineData("##.#", 65747.125f, "65747.1")]
+ [InlineData("##.#", 429496.72f, "429496.7")]
+ [InlineData("#,###.00", float.Epsilon, ".00")]
+ [InlineData("#,###.00", float.MaxValue, "340,282,300,000,000,000,000,000,000,000,000,000,000.00")]
+ [InlineData("#,###.00", MathF.E, "2.72")]
+ [InlineData("#,###.00", MathF.PI, "3.14")]
+ [InlineData("#,###.00", 0.0f, ".00")]
+ [InlineData("#,###.00", 0.0046f, ".00")]
+ [InlineData("#,###.00", 0.005f, ".01")]
+ [InlineData("#,###.00", 0.125f, ".13")]
+ [InlineData("#,###.00", 0.5f, ".50")]
+ [InlineData("#,###.00", 0.51f, ".51")]
+ [InlineData("#,###.00", 0.56789f, ".57")]
+ [InlineData("#,###.00", 0.845512390f, ".85")]
+ [InlineData("#,###.00", 1.0f, "1.00")]
+ [InlineData("#,###.00", 46.5f, "46.50")]
+ [InlineData("#,###.00", 505.0f, "505.00")]
+ [InlineData("#,###.00", 506.0f, "506.00")]
+ [InlineData("#,###.00", 545.0f, "545.00")]
+ [InlineData("#,###.00", 545.1f, "545.10")]
+ [InlineData("#,###.00", 555.0f, "555.00")]
+ [InlineData("#,###.00", 46500.0f, "46,500.00")]
+ [InlineData("#,###.00", 65747.125f, "65,747.12")]
+ [InlineData("#,###.00", 429496.72f, "429,496.70")]
+ public void TestFormatteSingle_Custom(string format, float value, string expectedResult) => TestFormatterSingle_Standard(value, format, expectedResult);
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public class RealFormatterTests : RealFormatterTestsBase
- {
- // The actual tests are defined in: src\Common\tests\System\RealFormatterTestsBase.netcoreapp.cs
-
- protected override string InvariantToStringDouble(double d, string format)
- {
- return d.ToString(format, CultureInfo.InvariantCulture);
- }
-
- protected override string InvariantToStringSingle(float f, string format)
- {
- return f.ToString(format, CultureInfo.InvariantCulture);
- }
-
- [Theory]
- [InlineData("##.#", double.Epsilon, "")]
- [InlineData("##.#", double.MaxValue, "179769313486232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
- [InlineData("##.#", Math.E, "2.7")]
- [InlineData("##.#", Math.PI, "3.1")]
- [InlineData("##.#", 0.0, "")]
- [InlineData("##.#", 0.0046, "")]
- [InlineData("##.#", 0.005, "")]
- [InlineData("##.#", 0.125, ".1")]
- [InlineData("##.#", 0.5, ".5")]
- [InlineData("##.#", 0.51, ".5")]
- [InlineData("##.#", 0.56789, ".6")]
- [InlineData("##.#", 0.84551240822557006, ".8")]
- [InlineData("##.#", 1.0, "1")]
- [InlineData("##.#", 46.5f, "46.5")]
- [InlineData("##.#", 505.0, "505")]
- [InlineData("##.#", 506.0, "506")]
- [InlineData("##.#", 545.0, "545")]
- [InlineData("##.#", 545.1, "545.1")]
- [InlineData("##.#", 555.0, "555")]
- [InlineData("##.#", 46500.0f, "46500")]
- [InlineData("##.#", 65747.125, "65747.1")]
- [InlineData("##.#", 1844674407370955.25, "1844674407370960")]
- [InlineData("#,###.00", double.Epsilon, ".00")]
- [InlineData("#,###.00", double.MaxValue, "179,769,313,486,232,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.00")]
- [InlineData("#,###.00", Math.E, "2.72")]
- [InlineData("#,###.00", Math.PI, "3.14")]
- [InlineData("#,###.00", 0.0, ".00")]
- [InlineData("#,###.00", 0.0046, ".00")]
- [InlineData("#,###.00", 0.005, ".01")]
- [InlineData("#,###.00", 0.125, ".13")]
- [InlineData("#,###.00", 0.5, ".50")]
- [InlineData("#,###.00", 0.51, ".51")]
- [InlineData("#,###.00", 0.56789, ".57")]
- [InlineData("#,###.00", 0.84551240822557006, ".85")]
- [InlineData("#,###.00", 1.0, "1.00")]
- [InlineData("#,###.00", 46.5f, "46.50")]
- [InlineData("#,###.00", 505.0, "505.00")]
- [InlineData("#,###.00", 506.0, "506.00")]
- [InlineData("#,###.00", 545.0, "545.00")]
- [InlineData("#,###.00", 545.1, "545.10")]
- [InlineData("#,###.00", 555.0, "555.00")]
- [InlineData("#,###.00", 46500.0f, "46,500.00")]
- [InlineData("#,###.00", 65747.125, "65,747.13")]
- [InlineData("#,###.00", 1844674407370955.25, "1,844,674,407,370,960.00")]
- public void TestFormatterDouble_Custom(string format, double value, string expectedResult) => TestFormatterDouble_Standard(value, format, expectedResult);
-
- [Theory]
- [InlineData("##.#", float.Epsilon, "")]
- [InlineData("##.#", float.MaxValue, "340282300000000000000000000000000000000")]
- [InlineData("##.#", MathF.E, "2.7")]
- [InlineData("##.#", MathF.PI, "3.1")]
- [InlineData("##.#", 0.0f, "")]
- [InlineData("##.#", 0.0046f, "")]
- [InlineData("##.#", 0.005f, "")]
- [InlineData("##.#", 0.125f, ".1")]
- [InlineData("##.#", 0.5f, ".5")]
- [InlineData("##.#", 0.51f, ".5")]
- [InlineData("##.#", 0.56789f, ".6")]
- [InlineData("##.#", 0.845512390f, ".8")]
- [InlineData("##.#", 1.0f, "1")]
- [InlineData("##.#", 46.5f, "46.5")]
- [InlineData("##.#", 505.0f, "505")]
- [InlineData("##.#", 506.0f, "506")]
- [InlineData("##.#", 545.0f, "545")]
- [InlineData("##.#", 545.1f, "545.1")]
- [InlineData("##.#", 555.0f, "555")]
- [InlineData("##.#", 46500.0f, "46500")]
- [InlineData("##.#", 65747.125f, "65747.1")]
- [InlineData("##.#", 429496.72f, "429496.7")]
- [InlineData("#,###.00", float.Epsilon, ".00")]
- [InlineData("#,###.00", float.MaxValue, "340,282,300,000,000,000,000,000,000,000,000,000,000.00")]
- [InlineData("#,###.00", MathF.E, "2.72")]
- [InlineData("#,###.00", MathF.PI, "3.14")]
- [InlineData("#,###.00", 0.0f, ".00")]
- [InlineData("#,###.00", 0.0046f, ".00")]
- [InlineData("#,###.00", 0.005f, ".01")]
- [InlineData("#,###.00", 0.125f, ".13")]
- [InlineData("#,###.00", 0.5f, ".50")]
- [InlineData("#,###.00", 0.51f, ".51")]
- [InlineData("#,###.00", 0.56789f, ".57")]
- [InlineData("#,###.00", 0.845512390f, ".85")]
- [InlineData("#,###.00", 1.0f, "1.00")]
- [InlineData("#,###.00", 46.5f, "46.50")]
- [InlineData("#,###.00", 505.0f, "505.00")]
- [InlineData("#,###.00", 506.0f, "506.00")]
- [InlineData("#,###.00", 545.0f, "545.00")]
- [InlineData("#,###.00", 545.1f, "545.10")]
- [InlineData("#,###.00", 555.0f, "555.00")]
- [InlineData("#,###.00", 46500.0f, "46,500.00")]
- [InlineData("#,###.00", 65747.125f, "65,747.12")]
- [InlineData("#,###.00", 429496.72f, "429,496.70")]
- public void TestFormatteSingle_Custom(string format, float value, string expectedResult) => TestFormatterSingle_Standard(value, format, expectedResult);
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Xunit;
+
+namespace System.Reflection.Tests
+{
+ public static class BindingFlagsDoNotWrapTests
+ {
+ [Fact]
+ public static void MethodInvoke()
+ {
+ MethodInfo m = typeof(TestClass).GetMethod(nameof(TestClass.Moo), BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
+ TestDoNotWrap<MyException1>((bf) => m.Invoke(null, bf, null, Array.Empty<object>(), null));
+ }
+
+ [Fact]
+ public static void ConstructorInvoke()
+ {
+ ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public|BindingFlags.Instance, null, Array.Empty<Type>(), null);
+ TestDoNotWrap<MyException2>((bf) => c.Invoke(bf, null, Array.Empty<object>(), null));
+ }
+
+ [Fact]
+ public static void ConstructorInvokeStringCtor()
+ {
+ // Code coverage: Project N - String constructors go through a separate code path.
+ ConstructorInfo c = typeof(string).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(char[]), typeof(int), typeof(int) }, null);
+ TestDoNotWrap<ArgumentNullException>((bf) => c.Invoke(bf, null, new object[] { null, 0, 0 }, null));
+ }
+
+ [Fact]
+ public static void ConstructorInvokeUsingMethodInfoInvoke()
+ {
+ ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Array.Empty<Type>(), null);
+ TestDoNotWrap<MyException2>((bf) => c.Invoke(new TestClass(0), bf, null, Array.Empty<object>(), null));
+ }
+
+ [Fact]
+ public static void PropertyGet()
+ {
+ PropertyInfo p = typeof(TestClass).GetProperty(nameof(TestClass.MyProperty));
+ TestDoNotWrap<MyException3>((bf) => p.GetValue(null, bf, null, null, null));
+ }
+
+ [Fact]
+ public static void PropertySet()
+ {
+ PropertyInfo p = typeof(TestClass).GetProperty(nameof(TestClass.MyProperty));
+ TestDoNotWrap<MyException4>((bf) => p.SetValue(null, 42, bf, null, null, null));
+ }
+
+ [Fact]
+ public static void InvokeMember_Method()
+ {
+ Type t = typeof(TestClass);
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.InvokeMethod;
+ TestDoNotWrap<MyException1>((bf) => t.InvokeMember(nameof(TestClass.Moo), bf | flags, null, null, Array.Empty<object>(), null, null, null));
+ }
+
+ [Fact]
+ public static void InvokeMember_PropertyGet()
+ {
+ Type t = typeof(TestClass);
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.GetProperty;
+ TestDoNotWrap<MyException3>((bf) => t.InvokeMember(nameof(TestClass.MyProperty), bf | flags, null, null, Array.Empty<object>(), null, null, null));
+ }
+
+ [Fact]
+ public static void InvokeMember_PropertySet()
+ {
+ Type t = typeof(TestClass);
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.SetProperty;
+ TestDoNotWrap<MyException4>((bf) => t.InvokeMember(nameof(TestClass.MyProperty), bf | flags, null, null, new object[] { 42 }, null, null, null));
+ }
+
+ [Fact]
+ public static void ActivatorCreateInstance()
+ {
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+ TestDoNotWrap<MyException2>((bf) => Activator.CreateInstance(typeof(TestClass), bf | flags, null, Array.Empty<object>(), null, null));
+ }
+
+ [Fact]
+ public static void ActivatorCreateInstanceOneArgument()
+ {
+ // For code coverage on CoreCLR: Activator.CreateInstance with parameters uses different code path from one without parameters.
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+ TestDoNotWrap<MyException5>((bf) => Activator.CreateInstance(typeof(TestClass), bf | flags, null, new object[] { "Hello" }, null, null));
+ }
+
+ [Fact]
+ public static void ActivatorCreateInstanceCaching()
+ {
+ // For code coverage on CoreCLR: Activator.CreateInstance - second call after non-throwing call goes through a different path
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+ TestClassConditional.ThrowInConstructor = true;
+ TestDoNotWrap<MyException6>((bf) => Activator.CreateInstance(typeof(TestClassConditional), bf | flags, null, Array.Empty<object>(), null, null));
+
+ TestClassConditional.ThrowInConstructor = false;
+ Assert.True(Activator.CreateInstance(typeof(TestClassConditional), flags, null, Array.Empty<object>(), null, null) is TestClassConditional);
+
+ TestClassConditional.ThrowInConstructor = true;
+ TestDoNotWrap<MyException6>((bf) => Activator.CreateInstance(typeof(TestClassConditional), bf | flags, null, Array.Empty<object>(), null, null));
+ }
+
+ [Fact]
+ public static void ActivatorCreateInstance_BadCCtor()
+ {
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+ TestDoNotWrap<TypeInitializationException>((bf) => Activator.CreateInstance(typeof(TestClassBadCCtor), bf | flags, null, Array.Empty<object>(), null, null));
+ }
+
+ [Fact]
+ public static void AssemblyCreateInstance()
+ {
+ Assembly a = typeof(TestClass).Assembly;
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+ TestDoNotWrap<MyException2>((bf) => a.CreateInstance(typeof(TestClass).FullName, false, bf | flags, null, Array.Empty<object>(), null, null));
+ }
+
+ [Fact]
+ public static void AssemblyCreateInstance_BadCCtor()
+ {
+ Assembly a = typeof(TestClass).Assembly;
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+ TestDoNotWrap<TypeInitializationException>((bf) => a.CreateInstance(typeof(TestClassBadCCtor).FullName, false, bf | flags, null, Array.Empty<object>(), null, null));
+ }
+
+ private static void TestDoNotWrap<T>(Action<BindingFlags> action) where T : Exception
+ {
+ Assert.Throws<T>(() => action(BindingFlags.DoNotWrapExceptions));
+ TargetInvocationException tie = Assert.Throws<TargetInvocationException>(() => action(default(BindingFlags)));
+ Assert.Equal(typeof(T), tie.InnerException.GetType());
+ }
+
+ private sealed class TestClass
+ {
+ public TestClass() => throw new MyException2();
+ public TestClass(int _) { }
+ public TestClass(string s) => throw new MyException5();
+ public static void Moo() => throw new MyException1();
+ public static int MyProperty { get { throw new MyException3(); } set { throw new MyException4(); } }
+ }
+
+ public sealed class TestClassBadCCtor
+ {
+ public TestClassBadCCtor() { }
+
+ static TestClassBadCCtor()
+ {
+ throw new MyException1();
+ }
+ }
+
+ private sealed class TestClassConditional
+ {
+ public TestClassConditional() { if (ThrowInConstructor) throw new MyException6(); }
+
+ public static bool ThrowInConstructor;
+ }
+
+ private sealed class MyException1 : Exception { }
+ private sealed class MyException2 : Exception { }
+ private sealed class MyException3 : Exception { }
+ private sealed class MyException4 : Exception { }
+ private sealed class MyException5 : Exception { }
+ private sealed class MyException6 : Exception { }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using Xunit;
-
-namespace System.Reflection.Tests
-{
- public static class BindingFlagsDoNotWrapTests
- {
- [Fact]
- public static void MethodInvoke()
- {
- MethodInfo m = typeof(TestClass).GetMethod(nameof(TestClass.Moo), BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- TestDoNotWrap<MyException1>((bf) => m.Invoke(null, bf, null, Array.Empty<object>(), null));
- }
-
- [Fact]
- public static void ConstructorInvoke()
- {
- ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public|BindingFlags.Instance, null, Array.Empty<Type>(), null);
- TestDoNotWrap<MyException2>((bf) => c.Invoke(bf, null, Array.Empty<object>(), null));
- }
-
- [Fact]
- public static void ConstructorInvokeStringCtor()
- {
- // Code coverage: Project N - String constructors go through a separate code path.
- ConstructorInfo c = typeof(string).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(char[]), typeof(int), typeof(int) }, null);
- TestDoNotWrap<ArgumentNullException>((bf) => c.Invoke(bf, null, new object[] { null, 0, 0 }, null));
- }
-
- [Fact]
- public static void ConstructorInvokeUsingMethodInfoInvoke()
- {
- ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Array.Empty<Type>(), null);
- TestDoNotWrap<MyException2>((bf) => c.Invoke(new TestClass(0), bf, null, Array.Empty<object>(), null));
- }
-
- [Fact]
- public static void PropertyGet()
- {
- PropertyInfo p = typeof(TestClass).GetProperty(nameof(TestClass.MyProperty));
- TestDoNotWrap<MyException3>((bf) => p.GetValue(null, bf, null, null, null));
- }
-
- [Fact]
- public static void PropertySet()
- {
- PropertyInfo p = typeof(TestClass).GetProperty(nameof(TestClass.MyProperty));
- TestDoNotWrap<MyException4>((bf) => p.SetValue(null, 42, bf, null, null, null));
- }
-
- [Fact]
- public static void InvokeMember_Method()
- {
- Type t = typeof(TestClass);
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.InvokeMethod;
- TestDoNotWrap<MyException1>((bf) => t.InvokeMember(nameof(TestClass.Moo), bf | flags, null, null, Array.Empty<object>(), null, null, null));
- }
-
- [Fact]
- public static void InvokeMember_PropertyGet()
- {
- Type t = typeof(TestClass);
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.GetProperty;
- TestDoNotWrap<MyException3>((bf) => t.InvokeMember(nameof(TestClass.MyProperty), bf | flags, null, null, Array.Empty<object>(), null, null, null));
- }
-
- [Fact]
- public static void InvokeMember_PropertySet()
- {
- Type t = typeof(TestClass);
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.SetProperty;
- TestDoNotWrap<MyException4>((bf) => t.InvokeMember(nameof(TestClass.MyProperty), bf | flags, null, null, new object[] { 42 }, null, null, null));
- }
-
- [Fact]
- public static void ActivatorCreateInstance()
- {
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- TestDoNotWrap<MyException2>((bf) => Activator.CreateInstance(typeof(TestClass), bf | flags, null, Array.Empty<object>(), null, null));
- }
-
- [Fact]
- public static void ActivatorCreateInstanceOneArgument()
- {
- // For code coverage on CoreCLR: Activator.CreateInstance with parameters uses different code path from one without parameters.
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- TestDoNotWrap<MyException5>((bf) => Activator.CreateInstance(typeof(TestClass), bf | flags, null, new object[] { "Hello" }, null, null));
- }
-
- [Fact]
- public static void ActivatorCreateInstanceCaching()
- {
- // For code coverage on CoreCLR: Activator.CreateInstance - second call after non-throwing call goes through a different path
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- TestClassConditional.ThrowInConstructor = true;
- TestDoNotWrap<MyException6>((bf) => Activator.CreateInstance(typeof(TestClassConditional), bf | flags, null, Array.Empty<object>(), null, null));
-
- TestClassConditional.ThrowInConstructor = false;
- Assert.True(Activator.CreateInstance(typeof(TestClassConditional), flags, null, Array.Empty<object>(), null, null) is TestClassConditional);
-
- TestClassConditional.ThrowInConstructor = true;
- TestDoNotWrap<MyException6>((bf) => Activator.CreateInstance(typeof(TestClassConditional), bf | flags, null, Array.Empty<object>(), null, null));
- }
-
- [Fact]
- public static void ActivatorCreateInstance_BadCCtor()
- {
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- TestDoNotWrap<TypeInitializationException>((bf) => Activator.CreateInstance(typeof(TestClassBadCCtor), bf | flags, null, Array.Empty<object>(), null, null));
- }
-
- [Fact]
- public static void AssemblyCreateInstance()
- {
- Assembly a = typeof(TestClass).Assembly;
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- TestDoNotWrap<MyException2>((bf) => a.CreateInstance(typeof(TestClass).FullName, false, bf | flags, null, Array.Empty<object>(), null, null));
- }
-
- [Fact]
- public static void AssemblyCreateInstance_BadCCtor()
- {
- Assembly a = typeof(TestClass).Assembly;
- const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- TestDoNotWrap<TypeInitializationException>((bf) => a.CreateInstance(typeof(TestClassBadCCtor).FullName, false, bf | flags, null, Array.Empty<object>(), null, null));
- }
-
- private static void TestDoNotWrap<T>(Action<BindingFlags> action) where T : Exception
- {
- Assert.Throws<T>(() => action(BindingFlags.DoNotWrapExceptions));
- TargetInvocationException tie = Assert.Throws<TargetInvocationException>(() => action(default(BindingFlags)));
- Assert.Equal(typeof(T), tie.InnerException.GetType());
- }
-
- private sealed class TestClass
- {
- public TestClass() => throw new MyException2();
- public TestClass(int _) { }
- public TestClass(string s) => throw new MyException5();
- public static void Moo() => throw new MyException1();
- public static int MyProperty { get { throw new MyException3(); } set { throw new MyException4(); } }
- }
-
- public sealed class TestClassBadCCtor
- {
- public TestClassBadCCtor() { }
-
- static TestClassBadCCtor()
- {
- throw new MyException1();
- }
- }
-
- private sealed class TestClassConditional
- {
- public TestClassConditional() { if (ThrowInConstructor) throw new MyException6(); }
-
- public static bool ThrowInConstructor;
- }
-
- private sealed class MyException1 : Exception { }
- private sealed class MyException2 : Exception { }
- private sealed class MyException3 : Exception { }
- private sealed class MyException4 : Exception { }
- private sealed class MyException5 : Exception { }
- private sealed class MyException6 : Exception { }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+using Xunit;
+
+namespace System.Reflection.Tests
+{
+ public class InvokeRefReturnNetcoreTests
+ {
+ [Theory]
+ [MemberData(nameof(RefReturnInvokeTestData))]
+ public static void TestRefReturnPropertyGetValue<T>(T value)
+ {
+ TestRefReturnInvoke<T>(value, (p, t) => p.GetValue(t));
+ }
+
+ [Theory]
+ [MemberData(nameof(RefReturnInvokeTestData))]
+ public static void TestRefReturnMethodInvoke<T>(T value)
+ {
+ TestRefReturnInvoke<T>(value, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>()));
+ }
+
+ [Fact]
+ public static void TestRefReturnNullable()
+ {
+ TestRefReturnInvokeNullable<int>(42);
+ }
+
+ [Fact]
+ public static void TestRefReturnNullableNoValue()
+ {
+ TestRefReturnInvokeNullable<int>(default(int?));
+ }
+
+ [Theory]
+ [MemberData(nameof(RefReturnInvokeTestData))]
+ public static void TestNullRefReturnInvoke<T>(T value)
+ {
+ TestClass<T> tc = new TestClass<T>(value);
+ PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.NullRefReturningProp));
+ Assert.NotNull(p);
+ Assert.Throws<NullReferenceException>(() => p.GetValue(tc));
+ }
+
+ [Fact]
+ public static unsafe void TestRefReturnOfPointer()
+ {
+ int* expected = (int*)0x1122334455667788;
+ TestClassIntPointer tc = new TestClassIntPointer(expected);
+ PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.RefReturningProp));
+ object rv = p.GetValue(tc);
+ Assert.True(rv is Pointer);
+ int* actual = (int*)(Pointer.Unbox(rv));
+ Assert.Equal((IntPtr)expected, (IntPtr)actual);
+ }
+
+ [Fact]
+ public static unsafe void TestNullRefReturnOfPointer()
+ {
+ TestClassIntPointer tc = new TestClassIntPointer(null);
+
+ PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.NullRefReturningProp));
+ Assert.NotNull(p);
+ Assert.Throws<NullReferenceException>(() => p.GetValue(tc));
+ }
+
+ [Fact]
+ public static unsafe void TestByRefLikeRefReturn()
+ {
+ ByRefLike brl = new ByRefLike();
+ ByRefLike* pBrl = &brl;
+ MethodInfo mi = typeof(TestClass<int>).GetMethod(nameof(TestClass<int>.ByRefLikeRefReturningMethod));
+ try
+ {
+ // Don't use Assert.Throws because that will make a lambda and invalidate the pointer
+ object o = mi.Invoke(null, new object[] { Pointer.Box(pBrl, typeof(ByRefLike*)) });
+
+ // If this is reached, it means `o` is a boxed byref-like type. That's a GC hole right there.
+ throw new Xunit.Sdk.XunitException("Boxed a byref-like type.");
+ }
+ catch (NotSupportedException)
+ {
+ // We expect a NotSupportedException from the Invoke call. Methods returning byref-like types by reference
+ // are not reflection invokable.
+ }
+ }
+
+ public static IEnumerable<object[]> RefReturnInvokeTestData
+ {
+ get
+ {
+ yield return new object[] { true };
+ yield return new object[] { 'a' };
+ yield return new object[] { (byte)42 };
+ yield return new object[] { (sbyte)42 };
+ yield return new object[] { (ushort)42 };
+ yield return new object[] { (short)42 };
+ yield return new object[] { 42u };
+ yield return new object[] { 42 };
+ yield return new object[] { 42UL };
+ yield return new object[] { 42L };
+ yield return new object[] { 43.67f };
+ yield return new object[] { 43.67 };
+ // [ActiveIssue("https://github.com/xunit/xunit/issues/1771")]
+ //yield return new object[] { new IntPtr(42) };
+ //yield return new object[] { new UIntPtr(42) };
+ //yield return new object[] { 232953453454m };
+ yield return new object[] { BindingFlags.IgnoreCase };
+ yield return new object[] { "Hello" };
+ yield return new object[] { new object() };
+ yield return new object[] { new UriBuilder() };
+ yield return new object[] { new int[5] };
+ yield return new object[] { new int[5, 5] };
+ }
+ }
+
+ private static void TestRefReturnInvoke<T>(T value, Func<PropertyInfo, TestClass<T>, object> invoker)
+ {
+ TestClass<T> tc = new TestClass<T>(value);
+ PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.RefReturningProp));
+ object rv = invoker(p, tc);
+ if (rv != null)
+ {
+ Assert.Equal(typeof(T), rv.GetType());
+ }
+
+ if (typeof(T).IsValueType)
+ {
+ Assert.Equal(value, rv);
+ }
+ else
+ {
+ Assert.Same((object)value, rv);
+ }
+ }
+
+ private static void TestRefReturnInvokeNullable<T>(T? nullable) where T : struct
+ {
+ TestClass<T?> tc = new TestClass<T?>(nullable);
+ PropertyInfo p = typeof(TestClass<T?>).GetProperty(nameof(TestClass<T?>.RefReturningProp));
+ object rv = p.GetValue(tc);
+ if (rv != null)
+ {
+ Assert.Equal(typeof(T), rv.GetType());
+ }
+ if (nullable.HasValue)
+ {
+ Assert.Equal(nullable.Value, rv);
+ }
+ else
+ {
+ Assert.Null(rv);
+ }
+ }
+
+ public ref struct ByRefLike { }
+
+ private sealed class TestClass<T>
+ {
+ private T _value;
+
+ public TestClass(T value) { _value = value; }
+ public ref T RefReturningProp => ref _value;
+ public unsafe ref T NullRefReturningProp => ref Unsafe.AsRef<T>((void*)null);
+ public static unsafe ref ByRefLike ByRefLikeRefReturningMethod(ByRefLike* a) => ref *a;
+ }
+
+ private sealed unsafe class TestClassIntPointer
+ {
+ private int* _value;
+
+ public TestClassIntPointer(int* value) { _value = value; }
+ public ref int* RefReturningProp => ref _value;
+ public ref int* NullRefReturningProp => ref *(int**)null;
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-
-using Xunit;
-
-namespace System.Reflection.Tests
-{
- public class InvokeRefReturnNetcoreTests
- {
- [Theory]
- [MemberData(nameof(RefReturnInvokeTestData))]
- public static void TestRefReturnPropertyGetValue<T>(T value)
- {
- TestRefReturnInvoke<T>(value, (p, t) => p.GetValue(t));
- }
-
- [Theory]
- [MemberData(nameof(RefReturnInvokeTestData))]
- public static void TestRefReturnMethodInvoke<T>(T value)
- {
- TestRefReturnInvoke<T>(value, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>()));
- }
-
- [Fact]
- public static void TestRefReturnNullable()
- {
- TestRefReturnInvokeNullable<int>(42);
- }
-
- [Fact]
- public static void TestRefReturnNullableNoValue()
- {
- TestRefReturnInvokeNullable<int>(default(int?));
- }
-
- [Theory]
- [MemberData(nameof(RefReturnInvokeTestData))]
- public static void TestNullRefReturnInvoke<T>(T value)
- {
- TestClass<T> tc = new TestClass<T>(value);
- PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.NullRefReturningProp));
- Assert.NotNull(p);
- Assert.Throws<NullReferenceException>(() => p.GetValue(tc));
- }
-
- [Fact]
- public static unsafe void TestRefReturnOfPointer()
- {
- int* expected = (int*)0x1122334455667788;
- TestClassIntPointer tc = new TestClassIntPointer(expected);
- PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.RefReturningProp));
- object rv = p.GetValue(tc);
- Assert.True(rv is Pointer);
- int* actual = (int*)(Pointer.Unbox(rv));
- Assert.Equal((IntPtr)expected, (IntPtr)actual);
- }
-
- [Fact]
- public static unsafe void TestNullRefReturnOfPointer()
- {
- TestClassIntPointer tc = new TestClassIntPointer(null);
-
- PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.NullRefReturningProp));
- Assert.NotNull(p);
- Assert.Throws<NullReferenceException>(() => p.GetValue(tc));
- }
-
- [Fact]
- public static unsafe void TestByRefLikeRefReturn()
- {
- ByRefLike brl = new ByRefLike();
- ByRefLike* pBrl = &brl;
- MethodInfo mi = typeof(TestClass<int>).GetMethod(nameof(TestClass<int>.ByRefLikeRefReturningMethod));
- try
- {
- // Don't use Assert.Throws because that will make a lambda and invalidate the pointer
- object o = mi.Invoke(null, new object[] { Pointer.Box(pBrl, typeof(ByRefLike*)) });
-
- // If this is reached, it means `o` is a boxed byref-like type. That's a GC hole right there.
- throw new Xunit.Sdk.XunitException("Boxed a byref-like type.");
- }
- catch (NotSupportedException)
- {
- // We expect a NotSupportedException from the Invoke call. Methods returning byref-like types by reference
- // are not reflection invokable.
- }
- }
-
- public static IEnumerable<object[]> RefReturnInvokeTestData
- {
- get
- {
- yield return new object[] { true };
- yield return new object[] { 'a' };
- yield return new object[] { (byte)42 };
- yield return new object[] { (sbyte)42 };
- yield return new object[] { (ushort)42 };
- yield return new object[] { (short)42 };
- yield return new object[] { 42u };
- yield return new object[] { 42 };
- yield return new object[] { 42UL };
- yield return new object[] { 42L };
- yield return new object[] { 43.67f };
- yield return new object[] { 43.67 };
- // [ActiveIssue("https://github.com/xunit/xunit/issues/1771")]
- //yield return new object[] { new IntPtr(42) };
- //yield return new object[] { new UIntPtr(42) };
- //yield return new object[] { 232953453454m };
- yield return new object[] { BindingFlags.IgnoreCase };
- yield return new object[] { "Hello" };
- yield return new object[] { new object() };
- yield return new object[] { new UriBuilder() };
- yield return new object[] { new int[5] };
- yield return new object[] { new int[5, 5] };
- }
- }
-
- private static void TestRefReturnInvoke<T>(T value, Func<PropertyInfo, TestClass<T>, object> invoker)
- {
- TestClass<T> tc = new TestClass<T>(value);
- PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.RefReturningProp));
- object rv = invoker(p, tc);
- if (rv != null)
- {
- Assert.Equal(typeof(T), rv.GetType());
- }
-
- if (typeof(T).IsValueType)
- {
- Assert.Equal(value, rv);
- }
- else
- {
- Assert.Same((object)value, rv);
- }
- }
-
- private static void TestRefReturnInvokeNullable<T>(T? nullable) where T : struct
- {
- TestClass<T?> tc = new TestClass<T?>(nullable);
- PropertyInfo p = typeof(TestClass<T?>).GetProperty(nameof(TestClass<T?>.RefReturningProp));
- object rv = p.GetValue(tc);
- if (rv != null)
- {
- Assert.Equal(typeof(T), rv.GetType());
- }
- if (nullable.HasValue)
- {
- Assert.Equal(nullable.Value, rv);
- }
- else
- {
- Assert.Null(rv);
- }
- }
-
- public ref struct ByRefLike { }
-
- private sealed class TestClass<T>
- {
- private T _value;
-
- public TestClass(T value) { _value = value; }
- public ref T RefReturningProp => ref _value;
- public unsafe ref T NullRefReturningProp => ref Unsafe.AsRef<T>((void*)null);
- public static unsafe ref ByRefLike ByRefLikeRefReturningMethod(ByRefLike* a) => ref *a;
- }
-
- private sealed unsafe class TestClassIntPointer
- {
- private int* _value;
-
- public TestClassIntPointer(int* value) { _value = value; }
- public ref int* RefReturningProp => ref _value;
- public ref int* NullRefReturningProp => ref *(int**)null;
- }
- }
-}
Assert.True(m.DeclaringType == typeof(MethodBaseTests));
}
- [Fact]
- public static void Test_GetCurrentMethod_GenericMethodDefinition()
- {
- MethodBase m = MyFakeGenericMethod<byte>();
-
- Assert.Equal("MyFakeGenericMethod", m.Name);
- Assert.Equal("MethodBaseTests", m.ReflectedType.Name);
- Assert.True(m.IsGenericMethod);
- Assert.True(m.IsGenericMethodDefinition);
- Assert.Equal(1, m.GetGenericArguments().Length);
- Assert.Equal("T", m.GetGenericArguments()[0].Name);
- }
-
[Fact]
public static void Test_GetCurrentMethod_Inlineable()
{
#endif
}
- public static MethodBase MyFakeGenericMethod<T>()
- {
- MethodBase m = MethodBase.GetCurrentMethod();
- return m;
- }
-
private static int MyAnotherMethod(int x)
{
return x+1;
}
}
#pragma warning restore xUnit1013 // Public method should be marked as test
+
+ [Fact]
+ public static void Test_GetCurrentMethod_ConstructedGenericMethod()
+ {
+ MethodInfo mi = typeof(MethodBaseTests).GetMethod(nameof(MyFakeGenericMethod), BindingFlags.NonPublic | BindingFlags.Static);
+ MethodBase m = mi.MakeGenericMethod(typeof(byte));
+
+ Assert.Equal(nameof(MyFakeGenericMethod), m.Name);
+ Assert.Equal(typeof(MethodBaseTests), m.ReflectedType);
+ Assert.True(m.IsGenericMethod);
+ Assert.False(m.IsGenericMethodDefinition);
+ Assert.True(m.IsConstructedGenericMethod);
+ Assert.Equal(1, m.GetGenericArguments().Length);
+ Assert.Equal(typeof(byte), m.GetGenericArguments()[0]);
+ }
+
+ [Fact]
+ public static void Test_GetCurrentMethod_GenericMethodDefinition()
+ {
+ MethodBase m = typeof(MethodBaseTests).GetMethod(nameof(MyFakeGenericMethod), BindingFlags.NonPublic | BindingFlags.Static);
+
+ Assert.Equal(nameof(MyFakeGenericMethod), m.Name);
+ Assert.Equal(typeof(MethodBaseTests), m.ReflectedType);
+ Assert.True(m.IsGenericMethod);
+ Assert.True(m.IsGenericMethodDefinition);
+ Assert.False(m.IsConstructedGenericMethod);
+ Assert.Equal(1, m.GetGenericArguments().Length);
+ Assert.Equal("T", m.GetGenericArguments()[0].Name);
+ }
+
+ private static void MyFakeGenericMethod<T>()
+ {
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Xunit;
-
-namespace System.Reflection.Tests
-{
- public class MethodBaseNetcoreTests
- {
- [Fact]
- public static void Test_GetCurrentMethod_ConstructedGenericMethod()
- {
- MethodInfo mi = typeof(MethodBaseNetcoreTests).GetMethod(nameof(MyFakeGenericMethod), BindingFlags.NonPublic | BindingFlags.Instance);
- MethodBase m = mi.MakeGenericMethod(typeof(byte));
-
- Assert.Equal(nameof(MyFakeGenericMethod), m.Name);
- Assert.Equal(typeof(MethodBaseNetcoreTests), m.ReflectedType);
- Assert.True(m.IsGenericMethod);
- Assert.False(m.IsGenericMethodDefinition);
- Assert.True(m.IsConstructedGenericMethod);
- Assert.Equal(1, m.GetGenericArguments().Length);
- Assert.Equal(typeof(byte), m.GetGenericArguments()[0]);
- }
-
- [Fact]
- public static void Test_GetCurrentMethod_GenericMethodDefinition()
- {
- MethodBase m = typeof(MethodBaseNetcoreTests).GetMethod(nameof(MyFakeGenericMethod), BindingFlags.NonPublic | BindingFlags.Instance);
-
- Assert.Equal(nameof(MyFakeGenericMethod), m.Name);
- Assert.Equal(typeof(MethodBaseNetcoreTests), m.ReflectedType);
- Assert.True(m.IsGenericMethod);
- Assert.True(m.IsGenericMethodDefinition);
- Assert.False(m.IsConstructedGenericMethod);
- Assert.Equal(1, m.GetGenericArguments().Length);
- Assert.Equal("T", m.GetGenericArguments()[0].Name);
- }
-
- private void MyFakeGenericMethod<T>()
- {
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Xunit;
+
+namespace System.Reflection.Tests
+{
+ public static class SignatureTypeTests
+ {
+ [Fact]
+ public static void IsSignatureType()
+ {
+ // Executing [Theory] logic manually. Signature Types cannot be used in theory data because Xunit preemptively invokes an unguarded
+ // System.Type pretty printer that invokes members that Signature Types don't support.
+ foreach (object[] pair in IsSignatureTypeTestData)
+ {
+ Type type = (Type)(pair[0]);
+ bool expected = (bool)(pair[1]);
+
+ Assert.Equal(expected, type.IsSignatureType);
+ }
+ }
+
+ public static IEnumerable<object[]> IsSignatureTypeTestData
+ {
+ get
+ {
+ yield return new object[] { typeof(int), false };
+ yield return new object[] { typeof(int).MakeArrayType(), false };
+ yield return new object[] { typeof(int).MakeArrayType(1), false };
+ yield return new object[] { typeof(int).MakeArrayType(2), false };
+ yield return new object[] { typeof(int).MakeByRefType(), false };
+ yield return new object[] { typeof(int).MakePointerType(), false };
+ yield return new object[] { typeof(List<>).MakeGenericType(typeof(int)), false };
+ yield return new object[] { typeof(List<>).GetGenericArguments()[0], false };
+
+ Type sigType = Type.MakeGenericMethodParameter(2);
+
+ yield return new object[] { sigType, true };
+ yield return new object[] { sigType.MakeArrayType(), true };
+ yield return new object[] { sigType.MakeArrayType(1), true };
+ yield return new object[] { sigType.MakeArrayType(2), true };
+ yield return new object[] { sigType.MakeByRefType(), true };
+ yield return new object[] { sigType.MakePointerType(), true };
+ yield return new object[] { typeof(List<>).MakeGenericType(sigType), true };
+
+ yield return new object[] { Type.MakeGenericSignatureType(typeof(List<>), typeof(int)), true };
+ yield return new object[] { Type.MakeGenericSignatureType(typeof(List<>), sigType), true };
+ }
+ }
+
+ [Fact]
+ public static void GetMethodWithGenericParameterCount()
+ {
+ Type t = typeof(TestClass1);
+ const BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
+ Type[] args = { typeof(int) };
+ MethodInfo m;
+
+ Assert.Throws<AmbiguousMatchException>(() => t.GetMethod("Moo", bf, null, args, null));
+
+ for (int genericParameterCount = 0; genericParameterCount < 4; genericParameterCount++)
+ {
+ m = t.GetMethod("Moo", genericParameterCount, bf, null, args, null);
+ Assert.NotNull(m);
+ AssertIsMarked(m, genericParameterCount);
+
+ // Verify that generic parameter count filtering occurs before candidates are passed to the binder.
+ m = t.GetMethod("Moo", genericParameterCount, bf, new InflexibleBinder(genericParameterCount), args, null);
+ Assert.NotNull(m);
+ AssertIsMarked(m, genericParameterCount);
+ }
+
+ m = t.GetMethod("Moo", 4, bf, null, args, null);
+ Assert.Null(m);
+ }
+
+ private sealed class InflexibleBinder : Binder
+ {
+ public InflexibleBinder(int genericParameterCount)
+ {
+ _genericParameterCount = genericParameterCount;
+ }
+
+ public sealed override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) => throw null;
+ public sealed override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) => throw null;
+ public sealed override object ChangeType(object value, Type type, CultureInfo culture) => throw null;
+ public sealed override void ReorderArgumentArray(ref object[] args, object state) => throw null;
+
+ public sealed override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
+ {
+ foreach (MethodBase methodBase in match)
+ {
+ Assert.True(methodBase is MethodInfo methodInfo && methodInfo.GetGenericArguments().Length == _genericParameterCount);
+ }
+ return Type.DefaultBinder.SelectMethod(bindingAttr, match, types, modifiers);
+ }
+
+ public sealed override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) { throw null; }
+
+ private readonly int _genericParameterCount;
+ }
+
+ [Fact]
+ public static void GetMethodWithNegativeGenericParameterCount()
+ {
+ Type t = typeof(TestClass1);
+ const BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
+ Type[] args = { typeof(int) };
+ Assert.Throws<ArgumentException>(() => t.GetMethod("Moo", -1, bf, null, args, null));
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void GetMethodOverloadTest(bool exactBinding)
+ {
+ Type t = typeof(TestClass2);
+ BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
+ if (exactBinding)
+ {
+ bf |= BindingFlags.ExactBinding;
+ }
+ Type[] args = { Type.MakeGenericMethodParameter(0), Type.MakeGenericMethodParameter(1).MakeArrayType() };
+ MethodInfo moo = t.GetMethod("Moo", 2, bf, null, args, null);
+ AssertIsMarked(moo, 3);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void SignatureTypeComparisonLogicCodeCoverage(bool exactBinding)
+ {
+ Type t = typeof(TestClass3<,>);
+ MethodInfo[] methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
+ BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
+ if (exactBinding)
+ {
+ bf |= BindingFlags.ExactBinding;
+ }
+
+ foreach (MethodInfo m in methods)
+ {
+ ParameterInfo[] parameters = m.GetParameters();
+ Type[] sigTypes = new Type[parameters.Length];
+ for (int i = 0; i < sigTypes.Length; i++)
+ {
+ sigTypes[i] = parameters[i].ParameterType.ToSignatureType();
+ }
+ MethodInfo match = t.GetMethod("Moo", m.GetGenericArguments().Length, bf, null, sigTypes, null);
+ Assert.NotNull(match);
+ Assert.True(m.HasSameMetadataDefinitionAs(match));
+ }
+ }
+
+ [Fact]
+ public static void SigTypeResolutionResilience()
+ {
+ // Make sure the framework can't be tricked into throwing an exception because it tried to look up a nonexistent method generic parameter
+ // or trying to construct a generic type where the constraints don't validate.
+ Type t = typeof(TestClass4<>);
+ Type[] args = { typeof(TestClass4<>).MakeGenericType(Type.MakeGenericMethodParameter(1)), Type.MakeGenericMethodParameter(500) };
+ CountingBinder binder = new CountingBinder();
+ Assert.Null(t.GetMethod("Moo", BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly, binder, args, null));
+ Assert.Equal(3, binder.NumCandidatesReceived);
+ }
+
+ private sealed class CountingBinder : Binder
+ {
+ public sealed override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) => throw null;
+ public sealed override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) => throw null;
+ public sealed override object ChangeType(object value, Type type, CultureInfo culture) => throw null;
+ public sealed override void ReorderArgumentArray(ref object[] args, object state) => throw null;
+
+ public sealed override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
+ {
+ NumCandidatesReceived += match.Length;
+ return Type.DefaultBinder.SelectMethod(bindingAttr, match, types, modifiers);
+ }
+
+ public sealed override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) { throw null; }
+
+ public int NumCandidatesReceived { get; private set; }
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(3)]
+ [InlineData(400)]
+ [InlineData(int.MaxValue)]
+ public static void MakeGenericMethodParameter(int position)
+ {
+ Type t = Type.MakeGenericMethodParameter(position);
+ Assert.True(t.IsGenericParameter);
+ Assert.False(t.IsGenericTypeParameter);
+ Assert.True(t.IsGenericMethodParameter);
+ Assert.Equal(position, t.GenericParameterPosition);
+ TestSignatureTypeInvariants(t);
+ }
+
+ [Theory]
+ [InlineData(-1)]
+ [InlineData(-5)]
+ [InlineData(int.MinValue)]
+ public static void MakeGenericMethodParameterNegative(int position)
+ {
+ Assert.Throws<ArgumentException>(() => Type.MakeGenericMethodParameter(position));
+ }
+
+ [Fact]
+ public static void MakeSignatureArrayType()
+ {
+ Type t = Type.MakeGenericMethodParameter(5);
+ t = t.MakeArrayType();
+ Assert.True(t.IsArray);
+ Assert.True(t.IsSZArray);
+ Assert.Equal(1, t.GetArrayRank());
+
+ Type et = t.GetElementType();
+ Assert.True(et.IsSignatureType);
+ Assert.True(et.IsGenericParameter);
+ Assert.False(et.IsGenericTypeParameter);
+ Assert.True(et.IsGenericMethodParameter);
+ Assert.Equal(5, et.GenericParameterPosition);
+
+ TestSignatureTypeInvariants(t);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ public static void MakeSignatureMdArrayType(int rank)
+ {
+ Type t = Type.MakeGenericMethodParameter(5);
+ t = t.MakeArrayType(rank);
+ Assert.True(t.IsArray);
+ Assert.True(t.IsVariableBoundArray);
+ Assert.Equal(rank, t.GetArrayRank());
+
+ TestSignatureTypeInvariants(t);
+ }
+
+ [Fact]
+ public static void MakeSignatureByRefType()
+ {
+ Type t = Type.MakeGenericMethodParameter(5);
+ t = t.MakeByRefType();
+ Assert.True(t.IsByRef);
+
+ Type et = t.GetElementType();
+ Assert.True(et.IsSignatureType);
+ Assert.True(et.IsGenericParameter);
+ Assert.False(et.IsGenericTypeParameter);
+ Assert.True(et.IsGenericMethodParameter);
+ Assert.Equal(5, et.GenericParameterPosition);
+
+ TestSignatureTypeInvariants(t);
+ }
+
+ [Fact]
+ public static void MakeSignaturePointerType()
+ {
+ Type t = Type.MakeGenericMethodParameter(5);
+ t = t.MakePointerType();
+ Assert.True(t.IsPointer);
+
+ Type et = t.GetElementType();
+ Assert.True(et.IsSignatureType);
+ Assert.True(et.IsGenericParameter);
+ Assert.False(et.IsGenericTypeParameter);
+ Assert.True(et.IsGenericMethodParameter);
+ Assert.Equal(5, et.GenericParameterPosition);
+
+ TestSignatureTypeInvariants(t);
+ }
+
+ [Theory]
+ [InlineData(typeof(List<>))]
+ [InlineData(typeof(Span<>))]
+ public static void MakeSignatureConstructedGenericType(Type genericTypeDefinition)
+ {
+ Type gmp = Type.MakeGenericMethodParameter(5);
+
+ Type[] testTypes = { genericTypeDefinition.MakeGenericType(gmp), Type.MakeGenericSignatureType(genericTypeDefinition, gmp) };
+ Assert.All(testTypes,
+ (Type t) =>
+ {
+ Assert.True(t.IsConstructedGenericType);
+ Assert.Equal(genericTypeDefinition, t.GetGenericTypeDefinition());
+ Assert.Equal(1, t.GenericTypeArguments.Length);
+
+ Type et = t.GenericTypeArguments[0];
+ Assert.True(et.IsSignatureType);
+ Assert.True(et.IsGenericParameter);
+ Assert.False(et.IsGenericTypeParameter);
+ Assert.True(et.IsGenericMethodParameter);
+ Assert.Equal(5, et.GenericParameterPosition);
+
+ TestSignatureTypeInvariants(t);
+ });
+ }
+
+ [Fact]
+ public static void MakeGenericSignatureTypeValidation()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("genericTypeDefinition", () => Type.MakeGenericSignatureType(null));
+ AssertExtensions.Throws<ArgumentNullException>("typeArguments", () => Type.MakeGenericSignatureType(typeof(IList<>), typeArguments: null));
+ AssertExtensions.Throws<ArgumentNullException>("typeArguments", () => Type.MakeGenericSignatureType(typeof(IList<>), new Type[] { null }));
+ }
+
+ private static Type ToSignatureType(this Type type)
+ {
+ if (type.IsTypeDefinition)
+ return type;
+ if (type.IsSZArray)
+ return type.GetElementType().ToSignatureType().MakeArrayType();
+ if (type.IsVariableBoundArray)
+ return type.GetElementType().ToSignatureType().MakeArrayType(type.GetArrayRank());
+ if (type.IsByRef)
+ return type.GetElementType().ToSignatureType().MakeByRefType();
+ if (type.IsPointer)
+ return type.GetElementType().ToSignatureType().MakePointerType();
+ if (type.IsConstructedGenericType)
+ {
+ Type[] genericTypeArguments = type.GenericTypeArguments.Select(t => t.ToSignatureType()).ToArray();
+ return type.GetGenericTypeDefinition().MakeGenericType(genericTypeArguments);
+ }
+ if (type.IsGenericTypeParameter)
+ return type;
+ if (type.IsGenericMethodParameter)
+ return Type.MakeGenericMethodParameter(type.GenericParameterPosition);
+
+ throw new Exception("Unknown type flavor.");
+ }
+
+ private static void AssertIsMarked(MemberInfo member, int value)
+ {
+ MarkerAttribute marker = member.GetCustomAttribute<MarkerAttribute>(inherit: false);
+ Assert.NotNull(marker);
+ Assert.Equal(value, marker.Value);
+ }
+
+ [AttributeUsage(AttributeTargets.All, Inherited = false)]
+ private sealed class MarkerAttribute : Attribute
+ {
+ public MarkerAttribute(int value)
+ {
+ Value = value;
+ }
+
+ public int Value { get; }
+ }
+
+ private sealed class TestClass1
+ {
+ [Marker(0)] public static void Moo(int x) { }
+ [Marker(1)] public static void Moo<T1>(int x) { }
+ [Marker(2)] public static void Moo<T1, T2>(int x) { }
+ [Marker(3)] public static void Moo<T1, T2, T3>(int x) {}
+ }
+
+ private class TestClass2
+ {
+ [Marker(0)] public static void Moo(int x, int[] y) { }
+ [Marker(1)] public static void Moo<T>(T x, T[] y) { }
+ [Marker(2)] public static void Moo<T>(int x, int[] y) { }
+ [Marker(3)] public static void Moo<T, U>(T x, U[] y) { }
+ [Marker(4)] public static void Moo<T, U>(int x, int[] y) { }
+ }
+
+ private class TestClass3<T,U>
+ {
+ public static void Moo(T p1, T[] p2, T[,] p3, ref T p4, TestClass3<T, T> p5, ref TestClass3<T, T[]>[,] p6) { }
+ public static void Moo(U p1, U[] p2, U[,] p3, ref U p4, TestClass3<U, U> p5, ref TestClass3<U, U[]>[,] p6) { }
+ public static void Moo<M>(T p1, T[] p2, T[,] p3, ref T p4, TestClass3<T, T> p5, ref TestClass3<T, T[]>[,] p6) { }
+ public static void Moo<M>(U p1, U[] p2, U[,] p3, ref U p4, TestClass3<U, U> p5, ref TestClass3<U, U[]>[,] p6) { }
+ public static void Moo<M>(M p1, M[] p2, M[,] p3, ref M p4, TestClass3<M, M> p5, ref TestClass3<M, M[]>[,] p6) { }
+ public static void Moo<M, N>(T p1, T[] p2, T[,] p3, ref T p4, TestClass3<T, T> p5, ref TestClass3<T, T[]>[,] p6) { }
+ public static void Moo<M, N>(U p1, U[] p2, U[,] p3, ref U p4, TestClass3<U, U> p5, ref TestClass3<U, U[]>[,] p6) { }
+ public static void Moo<M, N>(M p1, M[] p2, M[,] p3, ref M p4, TestClass3<M, M> p5, ref TestClass3<M, M[]>[,] p6) { }
+ public static void Moo<M, N>(N p1, N[] p2, N[,] p3, ref N p4, TestClass3<N, N> p5, ref TestClass3<N, N[]>[,] p6) { }
+ }
+
+ private class TestClass4<T> where T: NoOneSubclasses, new()
+ {
+ public static void Moo<M>(int p1, int p2) where M : NoOneSubclassesThisEither { }
+ public static void Moo<N, O>(TestClass4<N> p1, int p2) where N : NoOneSubclasses, new() { }
+ public static void Moo<N, O>(O p1, int p2) where N : NoOneSubclasses, new() { }
+ }
+
+ private class NoOneSubclasses { }
+ private class NoOneSubclassesThisEither { }
+
+ private static void TestSignatureTypeInvariants(Type type)
+ {
+ Assert.True(type.IsSignatureType);
+ Assert.False(type.IsTypeDefinition);
+ Assert.False(type.IsGenericTypeDefinition);
+ Assert.NotNull(type.Name);
+ Assert.Null(type.FullName);
+ Assert.Null(type.AssemblyQualifiedName);
+ Assert.NotNull(type.ToString());
+ Assert.Equal(MemberTypes.TypeInfo, type.MemberType);
+ Assert.Same(type, type.UnderlyingSystemType);
+
+ // SignatureTypes don't override Equality/GetHashCode at this time, but they don't promise never to do so either.
+ // Thus, we'll only test the most basic behavior.
+ Assert.True(type.Equals((object)type));
+ Assert.True(type.Equals((Type)type));
+ Assert.False(type.Equals((object)null));
+ Assert.False(type.Equals((Type)null));
+ int _ = type.GetHashCode();
+
+ bool categorized = false;
+ if (type.IsArray)
+ {
+ Assert.False(categorized);
+ categorized = true;
+ Assert.True(type.HasElementType);
+ Assert.True(type.IsSZArray != type.IsVariableBoundArray);
+ Assert.Equal(type.GetElementType().ContainsGenericParameters, type.ContainsGenericParameters);
+ string elementTypeName = type.GetElementType().Name;
+ if (type.IsSZArray)
+ {
+ Assert.Equal(1, type.GetArrayRank());
+
+ Assert.Equal(elementTypeName + "[]", type.Name);
+ }
+ else
+ {
+ int rank = type.GetArrayRank();
+ Assert.True(rank >= 1);
+ if (rank == 1)
+ {
+ Assert.Equal(elementTypeName + "[*]", type.Name);
+ }
+ else
+ {
+ Assert.Equal(elementTypeName + "[" + new string(',', rank - 1) + "]", type.Name);
+ }
+ }
+ }
+
+ if (type.IsByRef)
+ {
+ Assert.False(categorized);
+ categorized = true;
+
+ Assert.True(type.HasElementType);
+ Assert.Equal(type.GetElementType().ContainsGenericParameters, type.ContainsGenericParameters);
+ string elementTypeName = type.GetElementType().Name;
+ Assert.Equal(elementTypeName + "&", type.Name);
+ }
+
+ if (type.IsPointer)
+ {
+ Assert.False(categorized);
+ categorized = true;
+
+ Assert.True(type.HasElementType);
+ Assert.Equal(type.GetElementType().ContainsGenericParameters, type.ContainsGenericParameters);
+ string elementTypeName = type.GetElementType().Name;
+ Assert.Equal(elementTypeName + "*", type.Name);
+ }
+
+ if (type.IsConstructedGenericType)
+ {
+ Assert.False(categorized);
+ categorized = true;
+
+ Assert.True(type.IsGenericType);
+ Assert.False(type.HasElementType);
+ Type genericTypeDefinition = type.GetGenericTypeDefinition();
+ Assert.Equal(genericTypeDefinition.IsByRefLike, type.IsByRefLike);
+ Assert.NotNull(genericTypeDefinition);
+ Assert.True(genericTypeDefinition.IsGenericTypeDefinition);
+ Type[] genericTypeArguments = type.GetGenericArguments();
+ Type[] genericTypeArgumentsClone = type.GetGenericArguments();
+ Assert.NotSame(genericTypeArguments, genericTypeArgumentsClone);
+ Type[] genericTypeArgumentsFromProperty = type.GenericTypeArguments;
+ Type[] genericTypeArgumentsFromPropertyClone = type.GenericTypeArguments;
+ Assert.NotSame(genericTypeArgumentsFromProperty, genericTypeArgumentsFromPropertyClone);
+ for (int i = 0; i < genericTypeArguments.Length; i++)
+ {
+ if (genericTypeArguments[i].IsSignatureType)
+ {
+ TestSignatureTypeInvariants(genericTypeArguments[i]);
+ }
+ }
+ Assert.Equal(genericTypeDefinition.Name, type.Name);
+ Assert.Equal(genericTypeDefinition.Namespace, type.Namespace);
+
+
+ bool containsGenericParameters = false;
+ for (int i = 0; i < genericTypeArguments.Length; i++)
+ {
+ containsGenericParameters = containsGenericParameters || genericTypeArguments[i].ContainsGenericParameters;
+ }
+ Assert.Equal(containsGenericParameters, type.ContainsGenericParameters);
+ }
+
+ if (type.IsGenericParameter)
+ {
+ Assert.False(categorized);
+ categorized = true;
+
+ Assert.False(type.HasElementType);
+ Assert.True(type.ContainsGenericParameters);
+ Assert.Null(type.Namespace);
+
+ int position = type.GenericParameterPosition;
+ Assert.True(position >= 0);
+
+ if (type.IsGenericTypeParameter)
+ {
+ throw new Exception("Unexpected: There is no mechanism at this time to create Signature Types of generic parameters on types.");
+ }
+ else
+ {
+ Assert.True(type.IsGenericMethodParameter);
+ Assert.Equal("!!" + position, type.Name);
+ }
+ }
+
+ Assert.True(categorized);
+
+ if (type.HasElementType)
+ {
+ TestSignatureTypeInvariants(type.GetElementType());
+ Assert.Equal(type.GetElementType().Namespace, type.Namespace);
+ }
+ else
+ {
+ Assert.Null(type.GetElementType());
+ }
+
+ if (!type.IsConstructedGenericType)
+ {
+ Assert.Throws<InvalidOperationException>(() => type.GetGenericTypeDefinition());
+ Assert.Equal(0, type.GetGenericArguments().Length);
+ Assert.Equal(0, type.GenericTypeArguments.Length);
+ Assert.False(type.IsGenericType);
+ Assert.False(type.IsByRefLike);
+ }
+
+ if (!type.IsArray)
+ {
+ Assert.Throws<ArgumentException>(() => type.GetArrayRank());
+ }
+
+ if (!type.IsGenericParameter)
+ {
+ Assert.False(type.IsGenericTypeParameter);
+ Assert.False(type.IsGenericMethodParameter);
+ Assert.Throws<InvalidOperationException>(() => type.GenericParameterPosition);
+ }
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using Xunit;
-
-namespace System.Reflection.Tests
-{
- public static class SignatureTypeTests
- {
- [Fact]
- public static void IsSignatureType()
- {
- // Executing [Theory] logic manually. Signature Types cannot be used in theory data because Xunit preemptively invokes an unguarded
- // System.Type pretty printer that invokes members that Signature Types don't support.
- foreach (object[] pair in IsSignatureTypeTestData)
- {
- Type type = (Type)(pair[0]);
- bool expected = (bool)(pair[1]);
-
- Assert.Equal(expected, type.IsSignatureType);
- }
- }
-
- public static IEnumerable<object[]> IsSignatureTypeTestData
- {
- get
- {
- yield return new object[] { typeof(int), false };
- yield return new object[] { typeof(int).MakeArrayType(), false };
- yield return new object[] { typeof(int).MakeArrayType(1), false };
- yield return new object[] { typeof(int).MakeArrayType(2), false };
- yield return new object[] { typeof(int).MakeByRefType(), false };
- yield return new object[] { typeof(int).MakePointerType(), false };
- yield return new object[] { typeof(List<>).MakeGenericType(typeof(int)), false };
- yield return new object[] { typeof(List<>).GetGenericArguments()[0], false };
-
- Type sigType = Type.MakeGenericMethodParameter(2);
-
- yield return new object[] { sigType, true };
- yield return new object[] { sigType.MakeArrayType(), true };
- yield return new object[] { sigType.MakeArrayType(1), true };
- yield return new object[] { sigType.MakeArrayType(2), true };
- yield return new object[] { sigType.MakeByRefType(), true };
- yield return new object[] { sigType.MakePointerType(), true };
- yield return new object[] { typeof(List<>).MakeGenericType(sigType), true };
-
- yield return new object[] { Type.MakeGenericSignatureType(typeof(List<>), typeof(int)), true };
- yield return new object[] { Type.MakeGenericSignatureType(typeof(List<>), sigType), true };
- }
- }
-
- [Fact]
- public static void GetMethodWithGenericParameterCount()
- {
- Type t = typeof(TestClass1);
- const BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
- Type[] args = { typeof(int) };
- MethodInfo m;
-
- Assert.Throws<AmbiguousMatchException>(() => t.GetMethod("Moo", bf, null, args, null));
-
- for (int genericParameterCount = 0; genericParameterCount < 4; genericParameterCount++)
- {
- m = t.GetMethod("Moo", genericParameterCount, bf, null, args, null);
- Assert.NotNull(m);
- AssertIsMarked(m, genericParameterCount);
-
- // Verify that generic parameter count filtering occurs before candidates are passed to the binder.
- m = t.GetMethod("Moo", genericParameterCount, bf, new InflexibleBinder(genericParameterCount), args, null);
- Assert.NotNull(m);
- AssertIsMarked(m, genericParameterCount);
- }
-
- m = t.GetMethod("Moo", 4, bf, null, args, null);
- Assert.Null(m);
- }
-
- private sealed class InflexibleBinder : Binder
- {
- public InflexibleBinder(int genericParameterCount)
- {
- _genericParameterCount = genericParameterCount;
- }
-
- public sealed override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) => throw null;
- public sealed override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) => throw null;
- public sealed override object ChangeType(object value, Type type, CultureInfo culture) => throw null;
- public sealed override void ReorderArgumentArray(ref object[] args, object state) => throw null;
-
- public sealed override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
- {
- foreach (MethodBase methodBase in match)
- {
- Assert.True(methodBase is MethodInfo methodInfo && methodInfo.GetGenericArguments().Length == _genericParameterCount);
- }
- return Type.DefaultBinder.SelectMethod(bindingAttr, match, types, modifiers);
- }
-
- public sealed override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) { throw null; }
-
- private readonly int _genericParameterCount;
- }
-
- [Fact]
- public static void GetMethodWithNegativeGenericParameterCount()
- {
- Type t = typeof(TestClass1);
- const BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
- Type[] args = { typeof(int) };
- Assert.Throws<ArgumentException>(() => t.GetMethod("Moo", -1, bf, null, args, null));
- }
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void GetMethodOverloadTest(bool exactBinding)
- {
- Type t = typeof(TestClass2);
- BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
- if (exactBinding)
- {
- bf |= BindingFlags.ExactBinding;
- }
- Type[] args = { Type.MakeGenericMethodParameter(0), Type.MakeGenericMethodParameter(1).MakeArrayType() };
- MethodInfo moo = t.GetMethod("Moo", 2, bf, null, args, null);
- AssertIsMarked(moo, 3);
- }
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void SignatureTypeComparisonLogicCodeCoverage(bool exactBinding)
- {
- Type t = typeof(TestClass3<,>);
- MethodInfo[] methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
- BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
- if (exactBinding)
- {
- bf |= BindingFlags.ExactBinding;
- }
-
- foreach (MethodInfo m in methods)
- {
- ParameterInfo[] parameters = m.GetParameters();
- Type[] sigTypes = new Type[parameters.Length];
- for (int i = 0; i < sigTypes.Length; i++)
- {
- sigTypes[i] = parameters[i].ParameterType.ToSignatureType();
- }
- MethodInfo match = t.GetMethod("Moo", m.GetGenericArguments().Length, bf, null, sigTypes, null);
- Assert.NotNull(match);
- Assert.True(m.HasSameMetadataDefinitionAs(match));
- }
- }
-
- [Fact]
- public static void SigTypeResolutionResilience()
- {
- // Make sure the framework can't be tricked into throwing an exception because it tried to look up a nonexistent method generic parameter
- // or trying to construct a generic type where the constraints don't validate.
- Type t = typeof(TestClass4<>);
- Type[] args = { typeof(TestClass4<>).MakeGenericType(Type.MakeGenericMethodParameter(1)), Type.MakeGenericMethodParameter(500) };
- CountingBinder binder = new CountingBinder();
- Assert.Null(t.GetMethod("Moo", BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly, binder, args, null));
- Assert.Equal(3, binder.NumCandidatesReceived);
- }
-
- private sealed class CountingBinder : Binder
- {
- public sealed override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) => throw null;
- public sealed override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) => throw null;
- public sealed override object ChangeType(object value, Type type, CultureInfo culture) => throw null;
- public sealed override void ReorderArgumentArray(ref object[] args, object state) => throw null;
-
- public sealed override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
- {
- NumCandidatesReceived += match.Length;
- return Type.DefaultBinder.SelectMethod(bindingAttr, match, types, modifiers);
- }
-
- public sealed override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) { throw null; }
-
- public int NumCandidatesReceived { get; private set; }
- }
-
- [Theory]
- [InlineData(0)]
- [InlineData(3)]
- [InlineData(400)]
- [InlineData(int.MaxValue)]
- public static void MakeGenericMethodParameter(int position)
- {
- Type t = Type.MakeGenericMethodParameter(position);
- Assert.True(t.IsGenericParameter);
- Assert.False(t.IsGenericTypeParameter);
- Assert.True(t.IsGenericMethodParameter);
- Assert.Equal(position, t.GenericParameterPosition);
- TestSignatureTypeInvariants(t);
- }
-
- [Theory]
- [InlineData(-1)]
- [InlineData(-5)]
- [InlineData(int.MinValue)]
- public static void MakeGenericMethodParameterNegative(int position)
- {
- Assert.Throws<ArgumentException>(() => Type.MakeGenericMethodParameter(position));
- }
-
- [Fact]
- public static void MakeSignatureArrayType()
- {
- Type t = Type.MakeGenericMethodParameter(5);
- t = t.MakeArrayType();
- Assert.True(t.IsArray);
- Assert.True(t.IsSZArray);
- Assert.Equal(1, t.GetArrayRank());
-
- Type et = t.GetElementType();
- Assert.True(et.IsSignatureType);
- Assert.True(et.IsGenericParameter);
- Assert.False(et.IsGenericTypeParameter);
- Assert.True(et.IsGenericMethodParameter);
- Assert.Equal(5, et.GenericParameterPosition);
-
- TestSignatureTypeInvariants(t);
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(2)]
- [InlineData(3)]
- public static void MakeSignatureMdArrayType(int rank)
- {
- Type t = Type.MakeGenericMethodParameter(5);
- t = t.MakeArrayType(rank);
- Assert.True(t.IsArray);
- Assert.True(t.IsVariableBoundArray);
- Assert.Equal(rank, t.GetArrayRank());
-
- TestSignatureTypeInvariants(t);
- }
-
- [Fact]
- public static void MakeSignatureByRefType()
- {
- Type t = Type.MakeGenericMethodParameter(5);
- t = t.MakeByRefType();
- Assert.True(t.IsByRef);
-
- Type et = t.GetElementType();
- Assert.True(et.IsSignatureType);
- Assert.True(et.IsGenericParameter);
- Assert.False(et.IsGenericTypeParameter);
- Assert.True(et.IsGenericMethodParameter);
- Assert.Equal(5, et.GenericParameterPosition);
-
- TestSignatureTypeInvariants(t);
- }
-
- [Fact]
- public static void MakeSignaturePointerType()
- {
- Type t = Type.MakeGenericMethodParameter(5);
- t = t.MakePointerType();
- Assert.True(t.IsPointer);
-
- Type et = t.GetElementType();
- Assert.True(et.IsSignatureType);
- Assert.True(et.IsGenericParameter);
- Assert.False(et.IsGenericTypeParameter);
- Assert.True(et.IsGenericMethodParameter);
- Assert.Equal(5, et.GenericParameterPosition);
-
- TestSignatureTypeInvariants(t);
- }
-
- [Theory]
- [InlineData(typeof(List<>))]
- [InlineData(typeof(Span<>))]
- public static void MakeSignatureConstructedGenericType(Type genericTypeDefinition)
- {
- Type gmp = Type.MakeGenericMethodParameter(5);
-
- Type[] testTypes = { genericTypeDefinition.MakeGenericType(gmp), Type.MakeGenericSignatureType(genericTypeDefinition, gmp) };
- Assert.All(testTypes,
- (Type t) =>
- {
- Assert.True(t.IsConstructedGenericType);
- Assert.Equal(genericTypeDefinition, t.GetGenericTypeDefinition());
- Assert.Equal(1, t.GenericTypeArguments.Length);
-
- Type et = t.GenericTypeArguments[0];
- Assert.True(et.IsSignatureType);
- Assert.True(et.IsGenericParameter);
- Assert.False(et.IsGenericTypeParameter);
- Assert.True(et.IsGenericMethodParameter);
- Assert.Equal(5, et.GenericParameterPosition);
-
- TestSignatureTypeInvariants(t);
- });
- }
-
- [Fact]
- public static void MakeGenericSignatureTypeValidation()
- {
- AssertExtensions.Throws<ArgumentNullException>("genericTypeDefinition", () => Type.MakeGenericSignatureType(null));
- AssertExtensions.Throws<ArgumentNullException>("typeArguments", () => Type.MakeGenericSignatureType(typeof(IList<>), typeArguments: null));
- AssertExtensions.Throws<ArgumentNullException>("typeArguments", () => Type.MakeGenericSignatureType(typeof(IList<>), new Type[] { null }));
- }
-
- private static Type ToSignatureType(this Type type)
- {
- if (type.IsTypeDefinition)
- return type;
- if (type.IsSZArray)
- return type.GetElementType().ToSignatureType().MakeArrayType();
- if (type.IsVariableBoundArray)
- return type.GetElementType().ToSignatureType().MakeArrayType(type.GetArrayRank());
- if (type.IsByRef)
- return type.GetElementType().ToSignatureType().MakeByRefType();
- if (type.IsPointer)
- return type.GetElementType().ToSignatureType().MakePointerType();
- if (type.IsConstructedGenericType)
- {
- Type[] genericTypeArguments = type.GenericTypeArguments.Select(t => t.ToSignatureType()).ToArray();
- return type.GetGenericTypeDefinition().MakeGenericType(genericTypeArguments);
- }
- if (type.IsGenericTypeParameter)
- return type;
- if (type.IsGenericMethodParameter)
- return Type.MakeGenericMethodParameter(type.GenericParameterPosition);
-
- throw new Exception("Unknown type flavor.");
- }
-
- private static void AssertIsMarked(MemberInfo member, int value)
- {
- MarkerAttribute marker = member.GetCustomAttribute<MarkerAttribute>(inherit: false);
- Assert.NotNull(marker);
- Assert.Equal(value, marker.Value);
- }
-
- [AttributeUsage(AttributeTargets.All, Inherited = false)]
- private sealed class MarkerAttribute : Attribute
- {
- public MarkerAttribute(int value)
- {
- Value = value;
- }
-
- public int Value { get; }
- }
-
- private sealed class TestClass1
- {
- [Marker(0)] public static void Moo(int x) { }
- [Marker(1)] public static void Moo<T1>(int x) { }
- [Marker(2)] public static void Moo<T1, T2>(int x) { }
- [Marker(3)] public static void Moo<T1, T2, T3>(int x) {}
- }
-
- private class TestClass2
- {
- [Marker(0)] public static void Moo(int x, int[] y) { }
- [Marker(1)] public static void Moo<T>(T x, T[] y) { }
- [Marker(2)] public static void Moo<T>(int x, int[] y) { }
- [Marker(3)] public static void Moo<T, U>(T x, U[] y) { }
- [Marker(4)] public static void Moo<T, U>(int x, int[] y) { }
- }
-
- private class TestClass3<T,U>
- {
- public static void Moo(T p1, T[] p2, T[,] p3, ref T p4, TestClass3<T, T> p5, ref TestClass3<T, T[]>[,] p6) { }
- public static void Moo(U p1, U[] p2, U[,] p3, ref U p4, TestClass3<U, U> p5, ref TestClass3<U, U[]>[,] p6) { }
- public static void Moo<M>(T p1, T[] p2, T[,] p3, ref T p4, TestClass3<T, T> p5, ref TestClass3<T, T[]>[,] p6) { }
- public static void Moo<M>(U p1, U[] p2, U[,] p3, ref U p4, TestClass3<U, U> p5, ref TestClass3<U, U[]>[,] p6) { }
- public static void Moo<M>(M p1, M[] p2, M[,] p3, ref M p4, TestClass3<M, M> p5, ref TestClass3<M, M[]>[,] p6) { }
- public static void Moo<M, N>(T p1, T[] p2, T[,] p3, ref T p4, TestClass3<T, T> p5, ref TestClass3<T, T[]>[,] p6) { }
- public static void Moo<M, N>(U p1, U[] p2, U[,] p3, ref U p4, TestClass3<U, U> p5, ref TestClass3<U, U[]>[,] p6) { }
- public static void Moo<M, N>(M p1, M[] p2, M[,] p3, ref M p4, TestClass3<M, M> p5, ref TestClass3<M, M[]>[,] p6) { }
- public static void Moo<M, N>(N p1, N[] p2, N[,] p3, ref N p4, TestClass3<N, N> p5, ref TestClass3<N, N[]>[,] p6) { }
- }
-
- private class TestClass4<T> where T: NoOneSubclasses, new()
- {
- public static void Moo<M>(int p1, int p2) where M : NoOneSubclassesThisEither { }
- public static void Moo<N, O>(TestClass4<N> p1, int p2) where N : NoOneSubclasses, new() { }
- public static void Moo<N, O>(O p1, int p2) where N : NoOneSubclasses, new() { }
- }
-
- private class NoOneSubclasses { }
- private class NoOneSubclassesThisEither { }
-
- private static void TestSignatureTypeInvariants(Type type)
- {
- Assert.True(type.IsSignatureType);
- Assert.False(type.IsTypeDefinition);
- Assert.False(type.IsGenericTypeDefinition);
- Assert.NotNull(type.Name);
- Assert.Null(type.FullName);
- Assert.Null(type.AssemblyQualifiedName);
- Assert.NotNull(type.ToString());
- Assert.Equal(MemberTypes.TypeInfo, type.MemberType);
- Assert.Same(type, type.UnderlyingSystemType);
-
- // SignatureTypes don't override Equality/GetHashCode at this time, but they don't promise never to do so either.
- // Thus, we'll only test the most basic behavior.
- Assert.True(type.Equals((object)type));
- Assert.True(type.Equals((Type)type));
- Assert.False(type.Equals((object)null));
- Assert.False(type.Equals((Type)null));
- int _ = type.GetHashCode();
-
- bool categorized = false;
- if (type.IsArray)
- {
- Assert.False(categorized);
- categorized = true;
- Assert.True(type.HasElementType);
- Assert.True(type.IsSZArray != type.IsVariableBoundArray);
- Assert.Equal(type.GetElementType().ContainsGenericParameters, type.ContainsGenericParameters);
- string elementTypeName = type.GetElementType().Name;
- if (type.IsSZArray)
- {
- Assert.Equal(1, type.GetArrayRank());
-
- Assert.Equal(elementTypeName + "[]", type.Name);
- }
- else
- {
- int rank = type.GetArrayRank();
- Assert.True(rank >= 1);
- if (rank == 1)
- {
- Assert.Equal(elementTypeName + "[*]", type.Name);
- }
- else
- {
- Assert.Equal(elementTypeName + "[" + new string(',', rank - 1) + "]", type.Name);
- }
- }
- }
-
- if (type.IsByRef)
- {
- Assert.False(categorized);
- categorized = true;
-
- Assert.True(type.HasElementType);
- Assert.Equal(type.GetElementType().ContainsGenericParameters, type.ContainsGenericParameters);
- string elementTypeName = type.GetElementType().Name;
- Assert.Equal(elementTypeName + "&", type.Name);
- }
-
- if (type.IsPointer)
- {
- Assert.False(categorized);
- categorized = true;
-
- Assert.True(type.HasElementType);
- Assert.Equal(type.GetElementType().ContainsGenericParameters, type.ContainsGenericParameters);
- string elementTypeName = type.GetElementType().Name;
- Assert.Equal(elementTypeName + "*", type.Name);
- }
-
- if (type.IsConstructedGenericType)
- {
- Assert.False(categorized);
- categorized = true;
-
- Assert.True(type.IsGenericType);
- Assert.False(type.HasElementType);
- Type genericTypeDefinition = type.GetGenericTypeDefinition();
- Assert.Equal(genericTypeDefinition.IsByRefLike, type.IsByRefLike);
- Assert.NotNull(genericTypeDefinition);
- Assert.True(genericTypeDefinition.IsGenericTypeDefinition);
- Type[] genericTypeArguments = type.GetGenericArguments();
- Type[] genericTypeArgumentsClone = type.GetGenericArguments();
- Assert.NotSame(genericTypeArguments, genericTypeArgumentsClone);
- Type[] genericTypeArgumentsFromProperty = type.GenericTypeArguments;
- Type[] genericTypeArgumentsFromPropertyClone = type.GenericTypeArguments;
- Assert.NotSame(genericTypeArgumentsFromProperty, genericTypeArgumentsFromPropertyClone);
- for (int i = 0; i < genericTypeArguments.Length; i++)
- {
- if (genericTypeArguments[i].IsSignatureType)
- {
- TestSignatureTypeInvariants(genericTypeArguments[i]);
- }
- }
- Assert.Equal(genericTypeDefinition.Name, type.Name);
- Assert.Equal(genericTypeDefinition.Namespace, type.Namespace);
-
-
- bool containsGenericParameters = false;
- for (int i = 0; i < genericTypeArguments.Length; i++)
- {
- containsGenericParameters = containsGenericParameters || genericTypeArguments[i].ContainsGenericParameters;
- }
- Assert.Equal(containsGenericParameters, type.ContainsGenericParameters);
- }
-
- if (type.IsGenericParameter)
- {
- Assert.False(categorized);
- categorized = true;
-
- Assert.False(type.HasElementType);
- Assert.True(type.ContainsGenericParameters);
- Assert.Null(type.Namespace);
-
- int position = type.GenericParameterPosition;
- Assert.True(position >= 0);
-
- if (type.IsGenericTypeParameter)
- {
- throw new Exception("Unexpected: There is no mechanism at this time to create Signature Types of generic parameters on types.");
- }
- else
- {
- Assert.True(type.IsGenericMethodParameter);
- Assert.Equal("!!" + position, type.Name);
- }
- }
-
- Assert.True(categorized);
-
- if (type.HasElementType)
- {
- TestSignatureTypeInvariants(type.GetElementType());
- Assert.Equal(type.GetElementType().Namespace, type.Namespace);
- }
- else
- {
- Assert.Null(type.GetElementType());
- }
-
- if (!type.IsConstructedGenericType)
- {
- Assert.Throws<InvalidOperationException>(() => type.GetGenericTypeDefinition());
- Assert.Equal(0, type.GetGenericArguments().Length);
- Assert.Equal(0, type.GenericTypeArguments.Length);
- Assert.False(type.IsGenericType);
- Assert.False(type.IsByRefLike);
- }
-
- if (!type.IsArray)
- {
- Assert.Throws<ArgumentException>(() => type.GetArrayRank());
- }
-
- if (!type.IsGenericParameter)
- {
- Assert.False(type.IsGenericTypeParameter);
- Assert.False(type.IsGenericMethodParameter);
- Assert.Throws<InvalidOperationException>(() => type.GenericParameterPosition);
- }
- }
- }
-}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using Xunit;
namespace System.Reflection.Tests
Assert.True(new TypeDelegator(typeof(TypeCode)).IsValueType);
Assert.True(new TypeDelegator(typeof(TypeCode)).IsEnum);
}
+
+ public static IEnumerable<object[]> SZArrayOrNotTypes()
+ {
+ yield return new object[] { typeof(int[]), true };
+ yield return new object[] { typeof(string[]), true };
+ yield return new object[] { typeof(void), false };
+ yield return new object[] { typeof(int), false };
+ yield return new object[] { typeof(int[]).MakeByRefType(), false };
+ yield return new object[] { typeof(int[,]), false };
+ if (PlatformDetection.IsNonZeroLowerBoundArraySupported)
+ {
+ yield return new object[] { Array.CreateInstance(typeof(int), new[] { 2 }, new[] { -1 }).GetType(), false };
+ yield return new object[] { Array.CreateInstance(typeof(int), new[] { 2 }, new[] { 1 }).GetType(), false };
+ }
+ yield return new object[] { Array.CreateInstance(typeof(int), new[] { 2 }, new[] { 0 }).GetType(), true };
+ yield return new object[] { typeof(int[][]), true };
+ yield return new object[] { Type.GetType("System.Int32[]"), true };
+ yield return new object[] { Type.GetType("System.Int32[*]"), false };
+ yield return new object[] { Type.GetType("System.Int32"), false };
+ yield return new object[] { typeof(int).MakeArrayType(), true };
+ yield return new object[] { typeof(int).MakeArrayType(1), false };
+ yield return new object[] { typeof(int).MakeArrayType().MakeArrayType(), true };
+ yield return new object[] { typeof(int).MakeArrayType(2), false };
+ yield return new object[] { typeof(Outside<int>.Inside<string>), false };
+ yield return new object[] { typeof(Outside<int>.Inside<string>[]), true };
+ yield return new object[] { typeof(Outside<int>.Inside<string>[,]), false };
+ if (PlatformDetection.IsNonZeroLowerBoundArraySupported)
+ {
+ yield return new object[] { Array.CreateInstance(typeof(Outside<int>.Inside<string>), new[] { 2 }, new[] { -1 }).GetType(), false };
+ }
+ }
+
+ [Theory, MemberData(nameof(SZArrayOrNotTypes))]
+ public void IsSZArray(Type type, bool expected)
+ {
+ Assert.Equal(expected, new TypeDelegator(type).IsSZArray);
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using Xunit;
-
-namespace System.Reflection.Tests
-{
- public class TypeDelegatorNetcoreTests
- {
- public static IEnumerable<object[]> SZArrayOrNotTypes()
- {
- yield return new object[] { typeof(int[]), true };
- yield return new object[] { typeof(string[]), true };
- yield return new object[] { typeof(void), false };
- yield return new object[] { typeof(int), false };
- yield return new object[] { typeof(int[]).MakeByRefType(), false };
- yield return new object[] { typeof(int[,]), false };
- if (PlatformDetection.IsNonZeroLowerBoundArraySupported)
- {
- yield return new object[] { Array.CreateInstance(typeof(int), new[] { 2 }, new[] { -1 }).GetType(), false };
- yield return new object[] { Array.CreateInstance(typeof(int), new[] { 2 }, new[] { 1 }).GetType(), false };
- }
- yield return new object[] { Array.CreateInstance(typeof(int), new[] { 2 }, new[] { 0 }).GetType(), true };
- yield return new object[] { typeof(int[][]), true };
- yield return new object[] { Type.GetType("System.Int32[]"), true };
- yield return new object[] { Type.GetType("System.Int32[*]"), false };
- yield return new object[] { Type.GetType("System.Int32"), false };
- yield return new object[] { typeof(int).MakeArrayType(), true };
- yield return new object[] { typeof(int).MakeArrayType(1), false };
- yield return new object[] { typeof(int).MakeArrayType().MakeArrayType(), true };
- yield return new object[] { typeof(int).MakeArrayType(2), false };
- yield return new object[] { typeof(Outside<int>.Inside<string>), false };
- yield return new object[] { typeof(Outside<int>.Inside<string>[]), true };
- yield return new object[] { typeof(Outside<int>.Inside<string>[,]), false };
- if (PlatformDetection.IsNonZeroLowerBoundArraySupported)
- {
- yield return new object[] { Array.CreateInstance(typeof(Outside<int>.Inside<string>), new[] { 2 }, new[] { -1 }).GetType(), false };
- }
- }
-
- [Theory, MemberData(nameof(SZArrayOrNotTypes))]
- public void IsSZArray(Type type, bool expected)
- {
- Assert.Equal(expected, new TypeDelegator(type).IsSZArray);
- }
- }
-}
namespace System.Runtime.CompilerServices.Tests
{
- public static partial class AttributesTests
+ public static class AttributesTests
{
[Fact]
public static void AccessedThroughPropertyAttributeTests()
{
new UnsafeValueTypeAttribute();
}
+
+ [Fact]
+ public static void AsyncMethodBuilderAttributeTests()
+ {
+ var attr1 = new AsyncMethodBuilderAttribute(null);
+ Assert.Null(attr1.BuilderType);
+
+ var attr2 = new AsyncMethodBuilderAttribute(typeof(AttributesTests));
+ Assert.Equal(typeof(AttributesTests), attr2.BuilderType);
+ }
+
+ [Fact]
+ public static void IsByRefLikeAttributeTests()
+ {
+ new IsByRefLikeAttribute();
+ }
+
+ [Fact]
+ public static void IsReadOnlyAttributeTests()
+ {
+ new IsReadOnlyAttribute();
+ }
+
+ [Fact]
+ public static void EnumeratorCancellationAttributeTests()
+ {
+ new EnumeratorCancellationAttribute();
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Xunit;
-
-namespace System.Runtime.CompilerServices.Tests
-{
- public static partial class AttributesTests
- {
- [Fact]
- public static void AsyncMethodBuilderAttributeTests()
- {
- var attr1 = new AsyncMethodBuilderAttribute(null);
- Assert.Null(attr1.BuilderType);
-
- var attr2 = new AsyncMethodBuilderAttribute(typeof(AttributesTests));
- Assert.Equal(typeof(AttributesTests), attr2.BuilderType);
- }
-
- [Fact]
- public static void IsByRefLikeAttributeTests()
- {
- new IsByRefLikeAttribute();
- }
-
- [Fact]
- public static void IsReadOnlyAttributeTests()
- {
- new IsReadOnlyAttribute();
- }
-
- [Fact]
- public static void EnumeratorCancellationAttributeTests()
- {
- new EnumeratorCancellationAttribute();
- }
- }
-}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Linq;
+using System;
+using System.Collections.Generic;
using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace System.Runtime.CompilerServices.Tests
{
- public partial class ConditionalWeakTableTests
+ public class ConditionalWeakTableTests
{
[Fact]
public static void InvalidArgs_Throws()
// Do it a couple of times, to make sure the table is still usable after a clear.
}
}
+
+ [Fact]
+ public static void AddOrUpdateDataTest()
+ {
+ var cwt = new ConditionalWeakTable<string, string>();
+ string key = "key1";
+ cwt.AddOrUpdate(key, "value1");
+
+ string value;
+ Assert.True(cwt.TryGetValue(key, out value));
+ Assert.Equal("value1", value);
+ Assert.Equal(value, cwt.GetOrCreateValue(key));
+ Assert.Equal(value, cwt.GetValue(key, k => "value1"));
+
+ Assert.Throws<ArgumentNullException>(() => cwt.AddOrUpdate(null, "value2"));
+
+ cwt.AddOrUpdate(key, "value2");
+ Assert.True(cwt.TryGetValue(key, out value));
+ Assert.Equal("value2", value);
+ Assert.Equal(value, cwt.GetOrCreateValue(key));
+ Assert.Equal(value, cwt.GetValue(key, k => "value1"));
+ }
+
+ [Fact]
+ public static void Clear_EmptyTable()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ cwt.Clear(); // no exception
+ cwt.Clear();
+ }
+
+ [Fact]
+ public static void Clear_AddThenEmptyRepeatedly_ItemsRemoved()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ object key = new object(), value = new object();
+ object result;
+ for (int i = 0; i < 3; i++)
+ {
+ cwt.Add(key, value);
+
+ Assert.True(cwt.TryGetValue(key, out result));
+ Assert.Same(value, result);
+
+ cwt.Clear();
+
+ Assert.False(cwt.TryGetValue(key, out result));
+ Assert.Null(result);
+ }
+ }
+
+ [Fact]
+ public static void Clear_AddMany_Clear_AllItemsRemoved()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+
+ object[] keys = Enumerable.Range(0, 33).Select(_ => new object()).ToArray();
+ object[] values = Enumerable.Range(0, keys.Length).Select(_ => new object()).ToArray();
+ for (int i = 0; i < keys.Length; i++)
+ {
+ cwt.Add(keys[i], values[i]);
+ }
+
+ Assert.Equal(keys.Length, ((IEnumerable<KeyValuePair<object, object>>)cwt).Count());
+
+ cwt.Clear();
+
+ Assert.Equal(0, ((IEnumerable<KeyValuePair<object, object>>)cwt).Count());
+
+ GC.KeepAlive(keys);
+ GC.KeepAlive(values);
+ }
+
+ [Fact]
+ public static void GetEnumerator_Empty_ReturnsEmptyEnumerator()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+ Assert.Equal(0, enumerable.Count());
+ }
+
+ [Fact]
+ public static void GetEnumerator_AddedAndRemovedItems_AppropriatelyShowUpInEnumeration()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ object key1 = new object(), value1 = new object();
+
+ for (int i = 0; i < 20; i++) // adding and removing multiple times, across internal container boundary
+ {
+ cwt.Add(key1, value1);
+ Assert.Equal(1, enumerable.Count());
+ Assert.Equal(new KeyValuePair<object, object>(key1, value1), enumerable.First());
+
+ Assert.True(cwt.Remove(key1));
+ Assert.Equal(0, enumerable.Count());
+ }
+
+ GC.KeepAlive(key1);
+ GC.KeepAlive(value1);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))]
+ public static void GetEnumerator_CollectedItemsNotEnumerated()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ // Delegate to add collectible items to the table, separated out
+ // to avoid the JIT extending the lifetimes of the temporaries
+ Action<ConditionalWeakTable<object, object>> addItem =
+ t => t.Add(new object(), new object());
+
+ for (int i = 0; i < 10; i++) addItem(cwt);
+ GC.Collect();
+ Assert.Equal(0, enumerable.Count());
+ }
+
+ [Fact]
+ public static void GetEnumerator_MultipleEnumeratorsReturnSameResults()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ object[] keys = Enumerable.Range(0, 33).Select(_ => new object()).ToArray();
+ object[] values = Enumerable.Range(0, keys.Length).Select(_ => new object()).ToArray();
+ for (int i = 0; i < keys.Length; i++)
+ {
+ cwt.Add(keys[i], values[i]);
+ }
+
+ using (IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator())
+ using (IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator())
+ {
+ while (enumerator1.MoveNext())
+ {
+ Assert.True(enumerator2.MoveNext());
+ Assert.Equal(enumerator1.Current, enumerator2.Current);
+ }
+ Assert.False(enumerator2.MoveNext());
+ }
+
+ GC.KeepAlive(keys);
+ GC.KeepAlive(values);
+ }
+
+ [Fact]
+ public static void GetEnumerator_RemovedItems_RemovedFromResults()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ object[] keys = Enumerable.Range(0, 33).Select(_ => new object()).ToArray();
+ object[] values = Enumerable.Range(0, keys.Length).Select(_ => new object()).ToArray();
+ for (int i = 0; i < keys.Length; i++)
+ {
+ cwt.Add(keys[i], values[i]);
+ }
+
+ for (int i = 0; i < keys.Length; i++)
+ {
+ Assert.Equal(keys.Length - i, enumerable.Count());
+ Assert.Equal(
+ Enumerable.Range(i, keys.Length - i).Select(j => new KeyValuePair<object, object>(keys[j], values[j])),
+ enumerable);
+ cwt.Remove(keys[i]);
+ }
+ Assert.Equal(0, enumerable.Count());
+
+ GC.KeepAlive(keys);
+ GC.KeepAlive(values);
+ }
+
+ [Fact]
+ public static void GetEnumerator_ItemsAddedAfterGetEnumeratorNotIncluded()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object();
+
+ cwt.Add(key1, value1);
+ IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator();
+ cwt.Add(key2, value2);
+ IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator();
+
+ Assert.True(enumerator1.MoveNext());
+ Assert.Equal(new KeyValuePair<object, object>(key1, value1), enumerator1.Current);
+ Assert.False(enumerator1.MoveNext());
+
+ Assert.True(enumerator2.MoveNext());
+ Assert.Equal(new KeyValuePair<object, object>(key1, value1), enumerator2.Current);
+ Assert.True(enumerator2.MoveNext());
+ Assert.Equal(new KeyValuePair<object, object>(key2, value2), enumerator2.Current);
+ Assert.False(enumerator2.MoveNext());
+
+ enumerator1.Dispose();
+ enumerator2.Dispose();
+
+ GC.KeepAlive(key1);
+ GC.KeepAlive(key2);
+ GC.KeepAlive(value1);
+ GC.KeepAlive(value2);
+ }
+
+ [Fact]
+ public static void GetEnumerator_ItemsRemovedAfterGetEnumeratorNotIncluded()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object();
+
+ cwt.Add(key1, value1);
+ cwt.Add(key2, value2);
+ IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator();
+ cwt.Remove(key1);
+ IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator();
+
+ Assert.True(enumerator1.MoveNext());
+ Assert.Equal(new KeyValuePair<object, object>(key2, value2), enumerator1.Current);
+ Assert.False(enumerator1.MoveNext());
+
+ Assert.True(enumerator2.MoveNext());
+ Assert.Equal(new KeyValuePair<object, object>(key2, value2), enumerator2.Current);
+ Assert.False(enumerator2.MoveNext());
+
+ enumerator1.Dispose();
+ enumerator2.Dispose();
+
+ GC.KeepAlive(key1);
+ GC.KeepAlive(key2);
+ GC.KeepAlive(value1);
+ GC.KeepAlive(value2);
+ }
+
+ [Fact]
+ public static void GetEnumerator_ItemsClearedAfterGetEnumeratorNotIncluded()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object();
+
+ cwt.Add(key1, value1);
+ cwt.Add(key2, value2);
+ IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator();
+ cwt.Clear();
+ IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator();
+
+ Assert.False(enumerator1.MoveNext());
+ Assert.False(enumerator2.MoveNext());
+
+ enumerator1.Dispose();
+ enumerator2.Dispose();
+
+ GC.KeepAlive(key1);
+ GC.KeepAlive(key2);
+ GC.KeepAlive(value1);
+ GC.KeepAlive(value2);
+ }
+
+ [Fact]
+ public static void GetEnumerator_Current_ThrowsOnInvalidUse()
+ {
+ var cwt = new ConditionalWeakTable<object, object>();
+ var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
+
+ object key1 = new object(), value1 = new object();
+ cwt.Add(key1, value1);
+
+ using (IEnumerator<KeyValuePair<object, object>> enumerator = enumerable.GetEnumerator())
+ {
+ Assert.Throws<InvalidOperationException>(() => enumerator.Current); // before first MoveNext
+ }
+
+ GC.KeepAlive(key1);
+ GC.KeepAlive(value1);
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-using System.Linq;
-using Xunit;
-
-namespace System.Runtime.CompilerServices.Tests
-{
- public partial class ConditionalWeakTableTests
- {
- [Fact]
- public static void AddOrUpdateDataTest()
- {
- var cwt = new ConditionalWeakTable<string, string>();
- string key = "key1";
- cwt.AddOrUpdate(key, "value1");
-
- string value;
- Assert.True(cwt.TryGetValue(key, out value));
- Assert.Equal("value1", value);
- Assert.Equal(value, cwt.GetOrCreateValue(key));
- Assert.Equal(value, cwt.GetValue(key, k => "value1"));
-
- Assert.Throws<ArgumentNullException>(() => cwt.AddOrUpdate(null, "value2"));
-
- cwt.AddOrUpdate(key, "value2");
- Assert.True(cwt.TryGetValue(key, out value));
- Assert.Equal("value2", value);
- Assert.Equal(value, cwt.GetOrCreateValue(key));
- Assert.Equal(value, cwt.GetValue(key, k => "value1"));
- }
-
- [Fact]
- public static void Clear_EmptyTable()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- cwt.Clear(); // no exception
- cwt.Clear();
- }
-
- [Fact]
- public static void Clear_AddThenEmptyRepeatedly_ItemsRemoved()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- object key = new object(), value = new object();
- object result;
- for (int i = 0; i < 3; i++)
- {
- cwt.Add(key, value);
-
- Assert.True(cwt.TryGetValue(key, out result));
- Assert.Same(value, result);
-
- cwt.Clear();
-
- Assert.False(cwt.TryGetValue(key, out result));
- Assert.Null(result);
- }
- }
-
- [Fact]
- public static void Clear_AddMany_Clear_AllItemsRemoved()
- {
- var cwt = new ConditionalWeakTable<object, object>();
-
- object[] keys = Enumerable.Range(0, 33).Select(_ => new object()).ToArray();
- object[] values = Enumerable.Range(0, keys.Length).Select(_ => new object()).ToArray();
- for (int i = 0; i < keys.Length; i++)
- {
- cwt.Add(keys[i], values[i]);
- }
-
- Assert.Equal(keys.Length, ((IEnumerable<KeyValuePair<object, object>>)cwt).Count());
-
- cwt.Clear();
-
- Assert.Equal(0, ((IEnumerable<KeyValuePair<object, object>>)cwt).Count());
-
- GC.KeepAlive(keys);
- GC.KeepAlive(values);
- }
-
- [Fact]
- public static void GetEnumerator_Empty_ReturnsEmptyEnumerator()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
- Assert.Equal(0, enumerable.Count());
- }
-
- [Fact]
- public static void GetEnumerator_AddedAndRemovedItems_AppropriatelyShowUpInEnumeration()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- object key1 = new object(), value1 = new object();
-
- for (int i = 0; i < 20; i++) // adding and removing multiple times, across internal container boundary
- {
- cwt.Add(key1, value1);
- Assert.Equal(1, enumerable.Count());
- Assert.Equal(new KeyValuePair<object, object>(key1, value1), enumerable.First());
-
- Assert.True(cwt.Remove(key1));
- Assert.Equal(0, enumerable.Count());
- }
-
- GC.KeepAlive(key1);
- GC.KeepAlive(value1);
- }
-
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))]
- public static void GetEnumerator_CollectedItemsNotEnumerated()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- // Delegate to add collectible items to the table, separated out
- // to avoid the JIT extending the lifetimes of the temporaries
- Action<ConditionalWeakTable<object, object>> addItem =
- t => t.Add(new object(), new object());
-
- for (int i = 0; i < 10; i++) addItem(cwt);
- GC.Collect();
- Assert.Equal(0, enumerable.Count());
- }
-
- [Fact]
- public static void GetEnumerator_MultipleEnumeratorsReturnSameResults()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- object[] keys = Enumerable.Range(0, 33).Select(_ => new object()).ToArray();
- object[] values = Enumerable.Range(0, keys.Length).Select(_ => new object()).ToArray();
- for (int i = 0; i < keys.Length; i++)
- {
- cwt.Add(keys[i], values[i]);
- }
-
- using (IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator())
- using (IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator())
- {
- while (enumerator1.MoveNext())
- {
- Assert.True(enumerator2.MoveNext());
- Assert.Equal(enumerator1.Current, enumerator2.Current);
- }
- Assert.False(enumerator2.MoveNext());
- }
-
- GC.KeepAlive(keys);
- GC.KeepAlive(values);
- }
-
- [Fact]
- public static void GetEnumerator_RemovedItems_RemovedFromResults()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- object[] keys = Enumerable.Range(0, 33).Select(_ => new object()).ToArray();
- object[] values = Enumerable.Range(0, keys.Length).Select(_ => new object()).ToArray();
- for (int i = 0; i < keys.Length; i++)
- {
- cwt.Add(keys[i], values[i]);
- }
-
- for (int i = 0; i < keys.Length; i++)
- {
- Assert.Equal(keys.Length - i, enumerable.Count());
- Assert.Equal(
- Enumerable.Range(i, keys.Length - i).Select(j => new KeyValuePair<object, object>(keys[j], values[j])),
- enumerable);
- cwt.Remove(keys[i]);
- }
- Assert.Equal(0, enumerable.Count());
-
- GC.KeepAlive(keys);
- GC.KeepAlive(values);
- }
-
- [Fact]
- public static void GetEnumerator_ItemsAddedAfterGetEnumeratorNotIncluded()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object();
-
- cwt.Add(key1, value1);
- IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator();
- cwt.Add(key2, value2);
- IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator();
-
- Assert.True(enumerator1.MoveNext());
- Assert.Equal(new KeyValuePair<object, object>(key1, value1), enumerator1.Current);
- Assert.False(enumerator1.MoveNext());
-
- Assert.True(enumerator2.MoveNext());
- Assert.Equal(new KeyValuePair<object, object>(key1, value1), enumerator2.Current);
- Assert.True(enumerator2.MoveNext());
- Assert.Equal(new KeyValuePair<object, object>(key2, value2), enumerator2.Current);
- Assert.False(enumerator2.MoveNext());
-
- enumerator1.Dispose();
- enumerator2.Dispose();
-
- GC.KeepAlive(key1);
- GC.KeepAlive(key2);
- GC.KeepAlive(value1);
- GC.KeepAlive(value2);
- }
-
- [Fact]
- public static void GetEnumerator_ItemsRemovedAfterGetEnumeratorNotIncluded()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object();
-
- cwt.Add(key1, value1);
- cwt.Add(key2, value2);
- IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator();
- cwt.Remove(key1);
- IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator();
-
- Assert.True(enumerator1.MoveNext());
- Assert.Equal(new KeyValuePair<object, object>(key2, value2), enumerator1.Current);
- Assert.False(enumerator1.MoveNext());
-
- Assert.True(enumerator2.MoveNext());
- Assert.Equal(new KeyValuePair<object, object>(key2, value2), enumerator2.Current);
- Assert.False(enumerator2.MoveNext());
-
- enumerator1.Dispose();
- enumerator2.Dispose();
-
- GC.KeepAlive(key1);
- GC.KeepAlive(key2);
- GC.KeepAlive(value1);
- GC.KeepAlive(value2);
- }
-
- [Fact]
- public static void GetEnumerator_ItemsClearedAfterGetEnumeratorNotIncluded()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object();
-
- cwt.Add(key1, value1);
- cwt.Add(key2, value2);
- IEnumerator<KeyValuePair<object, object>> enumerator1 = enumerable.GetEnumerator();
- cwt.Clear();
- IEnumerator<KeyValuePair<object, object>> enumerator2 = enumerable.GetEnumerator();
-
- Assert.False(enumerator1.MoveNext());
- Assert.False(enumerator2.MoveNext());
-
- enumerator1.Dispose();
- enumerator2.Dispose();
-
- GC.KeepAlive(key1);
- GC.KeepAlive(key2);
- GC.KeepAlive(value1);
- GC.KeepAlive(value2);
- }
-
- [Fact]
- public static void GetEnumerator_Current_ThrowsOnInvalidUse()
- {
- var cwt = new ConditionalWeakTable<object, object>();
- var enumerable = (IEnumerable<KeyValuePair<object, object>>)cwt;
-
- object key1 = new object(), value1 = new object();
- cwt.Add(key1, value1);
-
- using (IEnumerator<KeyValuePair<object, object>> enumerator = enumerable.GetEnumerator())
- {
- Assert.Throws<InvalidOperationException>(() => enumerator.Current); // before first MoveNext
- }
-
- GC.KeepAlive(key1);
- GC.KeepAlive(value1);
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection;
+using Xunit;
+
+namespace System.Runtime.CompilerServices.Tests
+{
+ public static class MethodImplAttributeTests
+ {
+ [Fact]
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
+ public static void AggressiveOptimizationTest()
+ {
+ MethodImplAttributes implAttributes = MethodBase.GetCurrentMethod().MethodImplementationFlags;
+ Assert.Equal(MethodImplAttributes.AggressiveOptimization, implAttributes);
+ Assert.Equal(MethodImplOptions.AggressiveOptimization, (MethodImplOptions)implAttributes);
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Reflection;
-using Xunit;
-
-namespace System.Runtime.CompilerServices.Tests
-{
- public static class MethodImplAttributeTests
- {
- [Fact]
- [MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static void AggressiveOptimizationTest()
- {
- MethodImplAttributes implAttributes = MethodBase.GetCurrentMethod().MethodImplementationFlags;
- Assert.Equal(MethodImplAttributes.AggressiveOptimization, implAttributes);
- Assert.Equal(MethodImplOptions.AggressiveOptimization, (MethodImplOptions)implAttributes);
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+namespace System.Runtime.CompilerServices.Tests
+{
+ public static class RuntimeFeatureTests
+ {
+ [Fact]
+ public static void PortablePdb()
+ {
+ Assert.True(RuntimeFeature.IsSupported("PortablePdb"));
+ }
+
+ [Fact]
+ public static void DynamicCode()
+ {
+ Assert.Equal(RuntimeFeature.IsDynamicCodeSupported, RuntimeFeature.IsSupported("IsDynamicCodeSupported"));
+ Assert.Equal(RuntimeFeature.IsDynamicCodeCompiled, RuntimeFeature.IsSupported("IsDynamicCodeCompiled"));
+
+ if (RuntimeFeature.IsDynamicCodeCompiled)
+ {
+ Assert.True(RuntimeFeature.IsDynamicCodeSupported);
+ }
+ }
+
+ [Fact]
+ public static void DynamicCode_Jit()
+ {
+ Assert.True(RuntimeFeature.IsDynamicCodeSupported);
+ Assert.True(RuntimeFeature.IsDynamicCodeCompiled);
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.CompilerServices;
-using Xunit;
-
-namespace System.Runtime.CompilerServices.Tests
-{
- public static partial class RuntimeFeatureTests
- {
- [Fact]
- public static void PortablePdb()
- {
- Assert.True(RuntimeFeature.IsSupported("PortablePdb"));
- }
-
- [Fact]
- public static void DynamicCode()
- {
- Assert.Equal(RuntimeFeature.IsDynamicCodeSupported, RuntimeFeature.IsSupported("IsDynamicCodeSupported"));
- Assert.Equal(RuntimeFeature.IsDynamicCodeCompiled, RuntimeFeature.IsSupported("IsDynamicCodeCompiled"));
-
- if (RuntimeFeature.IsDynamicCodeCompiled)
- {
- Assert.True(RuntimeFeature.IsDynamicCodeSupported);
- }
- }
-
- [Fact]
- public static void DynamicCode_Jit()
- {
- Assert.True(RuntimeFeature.IsDynamicCodeSupported);
- Assert.True(RuntimeFeature.IsDynamicCodeCompiled);
- }
- }
-}
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Xunit;
namespace System.Runtime.CompilerServices.Tests
{
- public static partial class RuntimeHelpersTests
+ public static class RuntimeHelpersTests
{
[Fact]
public static void GetHashCodeTest()
RuntimeHelpers.PrepareDelegate((Func<int>)(() => 1) + (Func<int>)(() => 2));
RuntimeHelpers.PrepareDelegate(null);
}
- }
- public struct Age
- {
- public int years;
- public int months;
- }
+ [Fact]
+ public static void TryEnsureSufficientExecutionStack_SpaceAvailable_ReturnsTrue()
+ {
+ Assert.True(RuntimeHelpers.TryEnsureSufficientExecutionStack());
+ }
- public class FixedClass
- {
- [FixedAddressValueType]
- public static Age FixedAge;
+ [Fact]
+ public static void TryEnsureSufficientExecutionStack_NoSpaceAvailable_ReturnsFalse()
+ {
+ FillStack(depth: 0);
+ }
- public static unsafe IntPtr AddressOfFixedAge()
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void FillStack(int depth)
{
- fixed (Age* pointer = &FixedAge)
+ // This test will fail with a StackOverflowException if TryEnsureSufficientExecutionStack() doesn't
+ // return false. No exception is thrown and the test finishes when TryEnsureSufficientExecutionStack()
+ // returns true.
+ if (!RuntimeHelpers.TryEnsureSufficientExecutionStack())
{
- return (IntPtr)pointer;
+ Assert.Throws<InsufficientExecutionStackException>(() => RuntimeHelpers.EnsureSufficientExecutionStack());
+ return;
+ }
+ else if (depth < 2048)
+ {
+ FillStack(depth + 1);
}
}
- }
- public static partial class RuntimeHelpersTests
- {
+ [Fact]
+ public static void GetUninitializedObject_InvalidArguments_ThrowsException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("type", () => RuntimeHelpers.GetUninitializedObject(null));
+
+ AssertExtensions.Throws<ArgumentException>(null, () => RuntimeHelpers.GetUninitializedObject(typeof(string))); // special type
+ Assert.Throws<MemberAccessException>(() => RuntimeHelpers.GetUninitializedObject(typeof(System.IO.Stream))); // abstract type
+ Assert.Throws<MemberAccessException>(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.IEnumerable))); // interface
+ Assert.Throws<MemberAccessException>(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.Generic.List<>))); // generic definition
+ Assert.Throws<NotSupportedException>(() => RuntimeHelpers.GetUninitializedObject(typeof(TypedReference))); // byref-like type
+ }
+
+ [Fact]
+ public static void GetUninitializedObject_DoesNotRunConstructor()
+ {
+ Assert.Equal(42, new ObjectWithDefaultCtor().Value);
+ Assert.Equal(0, ((ObjectWithDefaultCtor)RuntimeHelpers.GetUninitializedObject(typeof(ObjectWithDefaultCtor))).Value);
+ }
+
+ [Fact]
+ public static void GetUninitializedObject_Nullable()
+ {
+ // Nullable returns the underlying type instead
+ Assert.Equal(typeof(int), RuntimeHelpers.GetUninitializedObject(typeof(Nullable<int>)).GetType());
+ }
+
+ private class ObjectWithDefaultCtor
+ {
+ public int Value = 42;
+ }
+
+ [Fact]
+ public static void IsReferenceOrContainsReferences()
+ {
+ Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences<int>());
+ Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences<string>());
+ Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences<Guid>());
+ Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences<StructWithoutReferences>());
+ Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences<StructWithReferences>());
+ }
+
+ [Fact]
+ public static void ArrayRangeHelperTest()
+ {
+ int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+ Range range = Range.All;
+ Assert.Equal(a, RuntimeHelpers.GetSubArray(a, range));
+
+ range = new Range(Index.FromStart(1), Index.FromEnd(5));
+ Assert.Equal(new int [] { 2, 3, 4, 5}, RuntimeHelpers.GetSubArray(a, range));
+
+ range = new Range(Index.FromStart(0), Index.FromStart(a.Length + 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => { int [] array = RuntimeHelpers.GetSubArray(a, range); });
+ }
+
+ [StructLayoutAttribute(LayoutKind.Sequential)]
+ private struct StructWithoutReferences
+ {
+ public int a, b, c;
+ }
+
+ [StructLayoutAttribute(LayoutKind.Sequential)]
+ private struct StructWithReferences
+ {
+ public int a, b, c;
+ public object d;
+ }
+
[Fact]
public static void FixedAddressValueTypeTest()
{
Assert.Equal(fixedPtr1, fixedPtr2);
}
}
+
+ public struct Age
+ {
+ public int years;
+ public int months;
+ }
+
+ public class FixedClass
+ {
+ [FixedAddressValueType]
+ public static Age FixedAge;
+
+ public static unsafe IntPtr AddressOfFixedAge()
+ {
+ fixed (Age* pointer = &FixedAge)
+ {
+ return (IntPtr)pointer;
+ }
+ }
+ }
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-
-using Xunit;
-
-namespace System.Runtime.CompilerServices.Tests
-{
- public static partial class RuntimeHelpersTests
- {
- [Fact]
- public static void TryEnsureSufficientExecutionStack_SpaceAvailable_ReturnsTrue()
- {
- Assert.True(RuntimeHelpers.TryEnsureSufficientExecutionStack());
- }
-
- [Fact]
- public static void TryEnsureSufficientExecutionStack_NoSpaceAvailable_ReturnsFalse()
- {
- FillStack(depth: 0);
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void FillStack(int depth)
- {
- // This test will fail with a StackOverflowException if TryEnsureSufficientExecutionStack() doesn't
- // return false. No exception is thrown and the test finishes when TryEnsureSufficientExecutionStack()
- // returns true.
- if (!RuntimeHelpers.TryEnsureSufficientExecutionStack())
- {
- Assert.Throws<InsufficientExecutionStackException>(() => RuntimeHelpers.EnsureSufficientExecutionStack());
- return;
- }
- else if (depth < 2048)
- {
- FillStack(depth + 1);
- }
- }
-
- [Fact]
- public static void GetUninitializedObject_InvalidArguments_ThrowsException()
- {
- AssertExtensions.Throws<ArgumentNullException>("type", () => RuntimeHelpers.GetUninitializedObject(null));
-
- AssertExtensions.Throws<ArgumentException>(null, () => RuntimeHelpers.GetUninitializedObject(typeof(string))); // special type
- Assert.Throws<MemberAccessException>(() => RuntimeHelpers.GetUninitializedObject(typeof(System.IO.Stream))); // abstract type
- Assert.Throws<MemberAccessException>(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.IEnumerable))); // interface
- Assert.Throws<MemberAccessException>(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.Generic.List<>))); // generic definition
- Assert.Throws<NotSupportedException>(() => RuntimeHelpers.GetUninitializedObject(typeof(TypedReference))); // byref-like type
- }
-
- [Fact]
- public static void GetUninitializedObject_DoesNotRunConstructor()
- {
- Assert.Equal(42, new ObjectWithDefaultCtor().Value);
- Assert.Equal(0, ((ObjectWithDefaultCtor)RuntimeHelpers.GetUninitializedObject(typeof(ObjectWithDefaultCtor))).Value);
- }
-
- [Fact]
- public static void GetUninitializedObject_Nullable()
- {
- // Nullable returns the underlying type instead
- Assert.Equal(typeof(int), RuntimeHelpers.GetUninitializedObject(typeof(Nullable<int>)).GetType());
- }
-
- private class ObjectWithDefaultCtor
- {
- public int Value = 42;
- }
-
- [Fact]
- public static void IsReferenceOrContainsReferences()
- {
- Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences<int>());
- Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences<string>());
- Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences<Guid>());
- Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences<StructWithoutReferences>());
- Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences<StructWithReferences>());
- }
-
- [Fact]
- public static void ArrayRangeHelperTest()
- {
- int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
- Range range = Range.All;
- Assert.Equal(a, RuntimeHelpers.GetSubArray(a, range));
-
- range = new Range(Index.FromStart(1), Index.FromEnd(5));
- Assert.Equal(new int [] { 2, 3, 4, 5}, RuntimeHelpers.GetSubArray(a, range));
-
- range = new Range(Index.FromStart(0), Index.FromStart(a.Length + 1));
- Assert.Throws<ArgumentOutOfRangeException>(() => { int [] array = RuntimeHelpers.GetSubArray(a, range); });
- }
-
- [StructLayoutAttribute(LayoutKind.Sequential)]
- private struct StructWithoutReferences
- {
- public int a, b, c;
- }
-
- [StructLayoutAttribute(LayoutKind.Sequential)]
- private struct StructWithReferences
- {
- public int a, b, c;
- public object d;
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using System.Text.RegularExpressions;
+using Xunit;
+
+namespace System.Runtime.ExceptionServices.Tests
+{
+ public class ExceptionDispatchInfoTests
+ {
+ [Fact]
+ public static void StaticThrow_NullArgument_ThrowArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ExceptionDispatchInfo.Throw(null));
+ }
+
+ [Fact]
+ public static void StaticThrow_UpdatesStackTraceAppropriately()
+ {
+ const string RethrowMessageSubstring = "End of stack trace";
+ var e = new FormatException();
+ for (int i = 0; i < 3; i++)
+ {
+ Assert.Same(e, Assert.Throws<FormatException>(() => ExceptionDispatchInfo.Throw(e)));
+ Assert.Equal(i, Regex.Matches(e.StackTrace, RethrowMessageSubstring).Count);
+ }
+ }
+
+ [Fact]
+ public static void SetCurrentStackTrace_Invalid_Throws()
+ {
+ Exception e;
+
+ // Null argument
+ e = null;
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+
+ // Previously set current stack
+ e = new Exception();
+ ExceptionDispatchInfo.SetCurrentStackTrace(e);
+ Assert.Throws<InvalidOperationException>(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+
+ // Previously thrown
+ e = new Exception();
+ try { throw e; } catch { }
+ Assert.Throws<InvalidOperationException>(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+ }
+
+ [Fact]
+ public static void SetCurrentStackTrace_IncludedInExceptionStackTrace()
+ {
+ Exception e;
+
+ e = new Exception();
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
+ Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
+
+ e = new Exception();
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
+ try { throw e; } catch { }
+ Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
+ private static void ABCDEFGHIJKLMNOPQRSTUVWXYZ(Exception e)
+ {
+ Assert.Same(e, ExceptionDispatchInfo.SetCurrentStackTrace(e));
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.ComponentModel;
-using System.Runtime.CompilerServices;
-using System.Text.RegularExpressions;
-using Xunit;
-
-namespace System.Runtime.ExceptionServices.Tests
-{
- public partial class ExceptionDispatchInfoTests
- {
- [Fact]
- public static void StaticThrow_NullArgument_ThrowArgumentNullException()
- {
- AssertExtensions.Throws<ArgumentNullException>("source", () => ExceptionDispatchInfo.Throw(null));
- }
-
- [Fact]
- public static void StaticThrow_UpdatesStackTraceAppropriately()
- {
- const string RethrowMessageSubstring = "End of stack trace";
- var e = new FormatException();
- for (int i = 0; i < 3; i++)
- {
- Assert.Same(e, Assert.Throws<FormatException>(() => ExceptionDispatchInfo.Throw(e)));
- Assert.Equal(i, Regex.Matches(e.StackTrace, RethrowMessageSubstring).Count);
- }
- }
-
- [Fact]
- public static void SetCurrentStackTrace_Invalid_Throws()
- {
- Exception e;
-
- // Null argument
- e = null;
- AssertExtensions.Throws<ArgumentNullException>("source", () => ExceptionDispatchInfo.SetCurrentStackTrace(e));
-
- // Previously set current stack
- e = new Exception();
- ExceptionDispatchInfo.SetCurrentStackTrace(e);
- Assert.Throws<InvalidOperationException>(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
-
- // Previously thrown
- e = new Exception();
- try { throw e; } catch { }
- Assert.Throws<InvalidOperationException>(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
- }
-
- [Fact]
- public static void SetCurrentStackTrace_IncludedInExceptionStackTrace()
- {
- Exception e;
-
- e = new Exception();
- ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
- Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
-
- e = new Exception();
- ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
- try { throw e; } catch { }
- Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
- }
-
- [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
- private static void ABCDEFGHIJKLMNOPQRSTUVWXYZ(Exception e)
- {
- Assert.Same(e, ExceptionDispatchInfo.SetCurrentStackTrace(e));
- }
- }
-}
AssertExtensions.Throws<ArgumentException>(paramName, () => sbyte.Parse("1", style));
AssertExtensions.Throws<ArgumentException>(paramName, () => sbyte.Parse("1", style, null));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "-123", 0, 2, NumberStyles.Integer, null, (sbyte)-1 };
+ yield return new object[] { "-123", 1, 3, NumberStyles.Integer, null, (sbyte)123 };
+ yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (sbyte)0x1 };
+ yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (sbyte)0x2 };
+ yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, null, (sbyte)123 };
+ yield return new object[] { "$100", 1, 1, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (sbyte)1 };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, sbyte expected)
+ {
+ sbyte result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(sbyte.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, sbyte.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(sbyte.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ sbyte result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(sbyte.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0, result);
+ }
+
+ Assert.Throws(exceptionType, () => sbyte.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(sbyte.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(sbyte i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class SByteTests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "-123", 0, 2, NumberStyles.Integer, null, (sbyte)-1 };
- yield return new object[] { "-123", 1, 3, NumberStyles.Integer, null, (sbyte)123 };
- yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (sbyte)0x1 };
- yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (sbyte)0x2 };
- yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, null, (sbyte)123 };
- yield return new object[] { "$100", 1, 1, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (sbyte)1 };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, sbyte expected)
- {
- sbyte result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(sbyte.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, sbyte.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(sbyte.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- sbyte result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(sbyte.TryParse(value.AsSpan(), out result));
- Assert.Equal(0, result);
- }
-
- Assert.Throws(exceptionType, () => sbyte.Parse(value.AsSpan(), style, provider));
-
- Assert.False(sbyte.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(sbyte i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
Assert.Throws<FormatException>(() => f.ToString("Y")); // Invalid format
Assert.Throws<FormatException>(() => f.ToString("Y", null)); // Invalid format
}
+
+ [Theory]
+ [InlineData(float.NegativeInfinity, false)] // Negative Infinity
+ [InlineData(float.MinValue, true)] // Min Negative Normal
+ [InlineData(-1.17549435E-38f, true)] // Max Negative Normal
+ [InlineData(-1.17549421E-38f, true)] // Min Negative Subnormal
+ [InlineData(-1.401298E-45, true)] // Max Negative Subnormal
+ [InlineData(-0.0f, true)] // Negative Zero
+ [InlineData(float.NaN, false)] // NaN
+ [InlineData(0.0f, true)] // Positive Zero
+ [InlineData(1.401298E-45, true)] // Min Positive Subnormal
+ [InlineData(1.17549421E-38f, true)] // Max Positive Subnormal
+ [InlineData(1.17549435E-38f, true)] // Min Positive Normal
+ [InlineData(float.MaxValue, true)] // Max Positive Normal
+ [InlineData(float.PositiveInfinity, false)] // Positive Infinity
+ public static void IsFinite(float d, bool expected)
+ {
+ Assert.Equal(expected, float.IsFinite(d));
+ }
+
+ [Theory]
+ [InlineData(float.NegativeInfinity, true)] // Negative Infinity
+ [InlineData(float.MinValue, true)] // Min Negative Normal
+ [InlineData(-1.17549435E-38f, true)] // Max Negative Normal
+ [InlineData(-1.17549421E-38f, true)] // Min Negative Subnormal
+ [InlineData(-1.401298E-45, true)] // Max Negative Subnormal
+ [InlineData(-0.0f, true)] // Negative Zero
+ [InlineData(float.NaN, true)] // NaN
+ [InlineData(0.0f, false)] // Positive Zero
+ [InlineData(1.401298E-45, false)] // Min Positive Subnormal
+ [InlineData(1.17549421E-38f, false)] // Max Positive Subnormal
+ [InlineData(1.17549435E-38f, false)] // Min Positive Normal
+ [InlineData(float.MaxValue, false)] // Max Positive Normal
+ [InlineData(float.PositiveInfinity, false)] // Positive Infinity
+ public static void IsNegative(float d, bool expected)
+ {
+ Assert.Equal(expected, float.IsNegative(d));
+ }
+
+ [Theory]
+ [InlineData(float.NegativeInfinity, false)] // Negative Infinity
+ [InlineData(float.MinValue, true)] // Min Negative Normal
+ [InlineData(-1.17549435E-38f, true)] // Max Negative Normal
+ [InlineData(-1.17549421E-38f, false)] // Min Negative Subnormal
+ [InlineData(-1.401298E-45, false)] // Max Negative Subnormal
+ [InlineData(-0.0f, false)] // Negative Zero
+ [InlineData(float.NaN, false)] // NaN
+ [InlineData(0.0f, false)] // Positive Zero
+ [InlineData(1.401298E-45, false)] // Min Positive Subnormal
+ [InlineData(1.17549421E-38f, false)] // Max Positive Subnormal
+ [InlineData(1.17549435E-38f, true)] // Min Positive Normal
+ [InlineData(float.MaxValue, true)] // Max Positive Normal
+ [InlineData(float.PositiveInfinity, false)] // Positive Infinity
+ public static void IsNormal(float d, bool expected)
+ {
+ Assert.Equal(expected, float.IsNormal(d));
+ }
+
+ [Theory]
+ [InlineData(float.NegativeInfinity, false)] // Negative Infinity
+ [InlineData(float.MinValue, false)] // Min Negative Normal
+ [InlineData(-1.17549435E-38f, false)] // Max Negative Normal
+ [InlineData(-1.17549421E-38f, true)] // Min Negative Subnormal
+ [InlineData(-1.401298E-45, true)] // Max Negative Subnormal
+ [InlineData(-0.0f, false)] // Negative Zero
+ [InlineData(float.NaN, false)] // NaN
+ [InlineData(0.0f, false)] // Positive Zero
+ [InlineData(1.401298E-45, true)] // Min Positive Subnormal
+ [InlineData(1.17549421E-38f, true)] // Max Positive Subnormal
+ [InlineData(1.17549435E-38f, false)] // Min Positive Normal
+ [InlineData(float.MaxValue, false)] // Max Positive Normal
+ [InlineData(float.PositiveInfinity, false)] // Positive Infinity
+ public static void IsSubnormal(float d, bool expected)
+ {
+ Assert.Equal(expected, float.IsSubnormal(d));
+ }
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ const NumberStyles DefaultStyle = NumberStyles.Float | NumberStyles.AllowThousands;
+
+ yield return new object[] { "-123", 1, 3, DefaultStyle, null, (float)123 };
+ yield return new object[] { "-123", 0, 3, DefaultStyle, null, (float)-12 };
+ yield return new object[] { "1E23", 0, 3, DefaultStyle, null, (float)1E2 };
+ yield return new object[] { "123", 0, 2, NumberStyles.Float, new NumberFormatInfo(), (float)12 };
+ yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$", CurrencyGroupSeparator = "," }, (float)10 };
+ yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, (float)123 };
+ yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, float.PositiveInfinity };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, float expected)
+ {
+ bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
+ float result;
+ if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None)
+ {
+ // Use Parse(string) or Parse(string, IFormatProvider)
+ if (isDefaultProvider)
+ {
+ Assert.True(float.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+
+ Assert.Equal(expected, float.Parse(value.AsSpan(offset, count)));
+ }
+
+ Assert.Equal(expected, float.Parse(value.AsSpan(offset, count), provider: provider));
+ }
+
+ Assert.Equal(expected, float.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(float.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ Assert.Throws(exceptionType, () => float.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(float.TryParse(value.AsSpan(), style, provider, out float result));
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Fact]
+ public static void TryFormat()
+ {
+ using (new ThreadCultureChange(CultureInfo.InvariantCulture))
+ {
+ foreach (object[] testdata in ToString_TestData())
+ {
+ float localI = (float)testdata[0];
+ string localFormat = (string)testdata[1];
+ IFormatProvider localProvider = (IFormatProvider)testdata[2];
+ string localExpected = (string)testdata[3];
+
+ try
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[localExpected.Length];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected, new string(actual));
+
+ // Longer than needed
+ actual = new char[localExpected.Length + 1];
+ Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(localExpected.Length, charsWritten);
+ Assert.Equal(localExpected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (localExpected.Length > 0)
+ {
+ actual = new char[localExpected.Length - 1];
+ Assert.False(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
+ Assert.Equal(0, charsWritten);
+ }
+ }
+ catch (Exception exc)
+ {
+ throw new Exception($"Failed on `{localI}`, `{localFormat}`, `{localProvider}`, `{localExpected}`. {exc}");
+ }
+ }
+ }
+ }
+
+ public static IEnumerable<object[]> ToStringRoundtrip_TestData()
+ {
+ yield return new object[] { float.NegativeInfinity };
+ yield return new object[] { float.MinValue };
+ yield return new object[] { -MathF.PI };
+ yield return new object[] { -MathF.E };
+ yield return new object[] { -float.Epsilon };
+ yield return new object[] { -0.845512408f };
+ yield return new object[] { -0.0f };
+ yield return new object[] { float.NaN };
+ yield return new object[] { 0.0f };
+ yield return new object[] { 0.845512408f };
+ yield return new object[] { float.Epsilon };
+ yield return new object[] { MathF.E };
+ yield return new object[] { MathF.PI };
+ yield return new object[] { float.MaxValue };
+ yield return new object[] { float.PositiveInfinity };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToStringRoundtrip_TestData))]
+ public static void ToStringRoundtrip(float value)
+ {
+ float result = float.Parse(value.ToString());
+ Assert.Equal(BitConverter.SingleToInt32Bits(value), BitConverter.SingleToInt32Bits(result));
+ }
+
+ [Theory]
+ [MemberData(nameof(ToStringRoundtrip_TestData))]
+ public static void ToStringRoundtrip_R(float value)
+ {
+ float result = float.Parse(value.ToString("R"));
+ Assert.Equal(BitConverter.SingleToInt32Bits(value), BitConverter.SingleToInt32Bits(result));
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-#pragma warning disable xUnit1025 // reporting duplicate test cases due to not distinguishing 0.0 from -0.0, NaN from -NaN
-
-namespace System.Tests
-{
- public partial class SingleTests
- {
- [Theory]
- [InlineData(float.NegativeInfinity, false)] // Negative Infinity
- [InlineData(float.MinValue, true)] // Min Negative Normal
- [InlineData(-1.17549435E-38f, true)] // Max Negative Normal
- [InlineData(-1.17549421E-38f, true)] // Min Negative Subnormal
- [InlineData(-1.401298E-45, true)] // Max Negative Subnormal
- [InlineData(-0.0f, true)] // Negative Zero
- [InlineData(float.NaN, false)] // NaN
- [InlineData(0.0f, true)] // Positive Zero
- [InlineData(1.401298E-45, true)] // Min Positive Subnormal
- [InlineData(1.17549421E-38f, true)] // Max Positive Subnormal
- [InlineData(1.17549435E-38f, true)] // Min Positive Normal
- [InlineData(float.MaxValue, true)] // Max Positive Normal
- [InlineData(float.PositiveInfinity, false)] // Positive Infinity
- public static void IsFinite(float d, bool expected)
- {
- Assert.Equal(expected, float.IsFinite(d));
- }
-
- [Theory]
- [InlineData(float.NegativeInfinity, true)] // Negative Infinity
- [InlineData(float.MinValue, true)] // Min Negative Normal
- [InlineData(-1.17549435E-38f, true)] // Max Negative Normal
- [InlineData(-1.17549421E-38f, true)] // Min Negative Subnormal
- [InlineData(-1.401298E-45, true)] // Max Negative Subnormal
- [InlineData(-0.0f, true)] // Negative Zero
- [InlineData(float.NaN, true)] // NaN
- [InlineData(0.0f, false)] // Positive Zero
- [InlineData(1.401298E-45, false)] // Min Positive Subnormal
- [InlineData(1.17549421E-38f, false)] // Max Positive Subnormal
- [InlineData(1.17549435E-38f, false)] // Min Positive Normal
- [InlineData(float.MaxValue, false)] // Max Positive Normal
- [InlineData(float.PositiveInfinity, false)] // Positive Infinity
- public static void IsNegative(float d, bool expected)
- {
- Assert.Equal(expected, float.IsNegative(d));
- }
-
- [Theory]
- [InlineData(float.NegativeInfinity, false)] // Negative Infinity
- [InlineData(float.MinValue, true)] // Min Negative Normal
- [InlineData(-1.17549435E-38f, true)] // Max Negative Normal
- [InlineData(-1.17549421E-38f, false)] // Min Negative Subnormal
- [InlineData(-1.401298E-45, false)] // Max Negative Subnormal
- [InlineData(-0.0f, false)] // Negative Zero
- [InlineData(float.NaN, false)] // NaN
- [InlineData(0.0f, false)] // Positive Zero
- [InlineData(1.401298E-45, false)] // Min Positive Subnormal
- [InlineData(1.17549421E-38f, false)] // Max Positive Subnormal
- [InlineData(1.17549435E-38f, true)] // Min Positive Normal
- [InlineData(float.MaxValue, true)] // Max Positive Normal
- [InlineData(float.PositiveInfinity, false)] // Positive Infinity
- public static void IsNormal(float d, bool expected)
- {
- Assert.Equal(expected, float.IsNormal(d));
- }
-
- [Theory]
- [InlineData(float.NegativeInfinity, false)] // Negative Infinity
- [InlineData(float.MinValue, false)] // Min Negative Normal
- [InlineData(-1.17549435E-38f, false)] // Max Negative Normal
- [InlineData(-1.17549421E-38f, true)] // Min Negative Subnormal
- [InlineData(-1.401298E-45, true)] // Max Negative Subnormal
- [InlineData(-0.0f, false)] // Negative Zero
- [InlineData(float.NaN, false)] // NaN
- [InlineData(0.0f, false)] // Positive Zero
- [InlineData(1.401298E-45, true)] // Min Positive Subnormal
- [InlineData(1.17549421E-38f, true)] // Max Positive Subnormal
- [InlineData(1.17549435E-38f, false)] // Min Positive Normal
- [InlineData(float.MaxValue, false)] // Max Positive Normal
- [InlineData(float.PositiveInfinity, false)] // Positive Infinity
- public static void IsSubnormal(float d, bool expected)
- {
- Assert.Equal(expected, float.IsSubnormal(d));
- }
-
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- const NumberStyles DefaultStyle = NumberStyles.Float | NumberStyles.AllowThousands;
-
- yield return new object[] { "-123", 1, 3, DefaultStyle, null, (float)123 };
- yield return new object[] { "-123", 0, 3, DefaultStyle, null, (float)-12 };
- yield return new object[] { "1E23", 0, 3, DefaultStyle, null, (float)1E2 };
- yield return new object[] { "123", 0, 2, NumberStyles.Float, new NumberFormatInfo(), (float)12 };
- yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$", CurrencyGroupSeparator = "," }, (float)10 };
- yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, (float)123 };
- yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, float.PositiveInfinity };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, float expected)
- {
- bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
- float result;
- if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None)
- {
- // Use Parse(string) or Parse(string, IFormatProvider)
- if (isDefaultProvider)
- {
- Assert.True(float.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
-
- Assert.Equal(expected, float.Parse(value.AsSpan(offset, count)));
- }
-
- Assert.Equal(expected, float.Parse(value.AsSpan(offset, count), provider: provider));
- }
-
- Assert.Equal(expected, float.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(float.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- Assert.Throws(exceptionType, () => float.Parse(value.AsSpan(), style, provider));
-
- Assert.False(float.TryParse(value.AsSpan(), style, provider, out float result));
- Assert.Equal(0, result);
- }
- }
-
- [Fact]
- public static void TryFormat()
- {
- using (new ThreadCultureChange(CultureInfo.InvariantCulture))
- {
- foreach (object[] testdata in ToString_TestData())
- {
- float localI = (float)testdata[0];
- string localFormat = (string)testdata[1];
- IFormatProvider localProvider = (IFormatProvider)testdata[2];
- string localExpected = (string)testdata[3];
-
- try
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[localExpected.Length];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected, new string(actual));
-
- // Longer than needed
- actual = new char[localExpected.Length + 1];
- Assert.True(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(localExpected.Length, charsWritten);
- Assert.Equal(localExpected, new string(actual, 0, charsWritten));
-
- // Too short
- if (localExpected.Length > 0)
- {
- actual = new char[localExpected.Length - 1];
- Assert.False(localI.TryFormat(actual.AsSpan(), out charsWritten, localFormat, localProvider));
- Assert.Equal(0, charsWritten);
- }
- }
- catch (Exception exc)
- {
- throw new Exception($"Failed on `{localI}`, `{localFormat}`, `{localProvider}`, `{localExpected}`. {exc}");
- }
- }
- }
- }
-
- public static IEnumerable<object[]> ToStringRoundtrip_TestData()
- {
- yield return new object[] { float.NegativeInfinity };
- yield return new object[] { float.MinValue };
- yield return new object[] { -MathF.PI };
- yield return new object[] { -MathF.E };
- yield return new object[] { -float.Epsilon };
- yield return new object[] { -0.845512408f };
- yield return new object[] { -0.0f };
- yield return new object[] { float.NaN };
- yield return new object[] { 0.0f };
- yield return new object[] { 0.845512408f };
- yield return new object[] { float.Epsilon };
- yield return new object[] { MathF.E };
- yield return new object[] { MathF.PI };
- yield return new object[] { float.MaxValue };
- yield return new object[] { float.PositiveInfinity };
- }
-
- [Theory]
- [MemberData(nameof(ToStringRoundtrip_TestData))]
- public static void ToStringRoundtrip(float value)
- {
- float result = float.Parse(value.ToString());
- Assert.Equal(BitConverter.SingleToInt32Bits(value), BitConverter.SingleToInt32Bits(result));
- }
-
- [Theory]
- [MemberData(nameof(ToStringRoundtrip_TestData))]
- public static void ToStringRoundtrip_R(float value)
- {
- float result = float.Parse(value.ToString("R"));
- Assert.Equal(BitConverter.SingleToInt32Bits(value), BitConverter.SingleToInt32Bits(result));
- }
- }
-}
namespace System.Tests
{
- public partial class StringComparerTests
+ public class StringComparerTests
{
[Fact]
public void Create_InvalidArguments_Throws()
Assert.False(c.Equals("42", 84));
Assert.False(c.Equals(42, "84"));
}
+
+ [Fact]
+ public void CreateCultureOptions_InvalidArguments_Throws()
+ {
+ Assert.Throws<ArgumentNullException>(() => StringComparer.Create(null, CompareOptions.None));
+ }
+
+ [Fact]
+ public void CreateCultureOptions_CreatesValidComparer()
+ {
+ StringComparer c = StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.IgnoreCase);
+ Assert.NotNull(c);
+ Assert.True(c.Equals((object)"hello", (object)"HEllO"));
+ Assert.True(c.Equals("hello", "HEllO"));
+ Assert.False(c.Equals((object)"bello", (object)"HEllO"));
+ Assert.False(c.Equals("bello", "HEllO"));
+
+ object obj = new object();
+ Assert.Equal(c.GetHashCode((object)"hello"), c.GetHashCode((object)"hello"));
+ Assert.Equal(c.GetHashCode("hello"), c.GetHashCode("hello"));
+ Assert.Equal(c.GetHashCode("hello"), c.GetHashCode((object)"hello"));
+ Assert.Equal(obj.GetHashCode(), c.GetHashCode(obj));
+ Assert.Equal(42.CompareTo(84), c.Compare(42, 84));
+ Assert.Throws<ArgumentException>(() => c.Compare("42", 84));
+ Assert.Equal(1, c.Compare("42", null));
+ Assert.Throws<ArgumentException>(() => c.Compare(42, "84"));
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class StringComparerTests
- {
- [Fact]
- public void CreateCultureOptions_InvalidArguments_Throws()
- {
- Assert.Throws<ArgumentNullException>(() => StringComparer.Create(null, CompareOptions.None));
- }
-
- [Fact]
- public void CreateCultureOptions_CreatesValidComparer()
- {
- StringComparer c = StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.IgnoreCase);
- Assert.NotNull(c);
- Assert.True(c.Equals((object)"hello", (object)"HEllO"));
- Assert.True(c.Equals("hello", "HEllO"));
- Assert.False(c.Equals((object)"bello", (object)"HEllO"));
- Assert.False(c.Equals("bello", "HEllO"));
-
- object obj = new object();
- Assert.Equal(c.GetHashCode((object)"hello"), c.GetHashCode((object)"hello"));
- Assert.Equal(c.GetHashCode("hello"), c.GetHashCode("hello"));
- Assert.Equal(c.GetHashCode("hello"), c.GetHashCode((object)"hello"));
- Assert.Equal(obj.GetHashCode(), c.GetHashCode(obj));
- Assert.Equal(42.CompareTo(84), c.Compare(42, 84));
- Assert.Throws<ArgumentException>(() => c.Compare("42", 84));
- Assert.Equal(1, c.Compare("42", null));
- Assert.Throws<ArgumentException>(() => c.Compare(42, "84"));
- }
- }
-}
namespace System.Tests
{
- public partial class StringGetHashCodeTests
+ public class StringGetHashCodeTests
{
/// <summary>
/// Ensure that hash codes are randomized by getting the hash in two processes
() => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.Ordinal); },
() => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.OrdinalIgnoreCase); }
};
+
+ [Theory]
+ [MemberData(nameof(GetHashCodeOrdinalIgnoreCase_TestData))]
+ public void GetHashCode_OrdinalIgnoreCase_ReturnsSameHashCodeAsUpperCaseOrdinal(string input)
+ {
+ // As an implementation detail, the OrdinalIgnoreCase hash code calculation is simply the hash code
+ // of the upper-invariant version of the input string.
+
+ Assert.Equal(input.ToUpperInvariant().GetHashCode(), input.GetHashCode(StringComparison.OrdinalIgnoreCase));
+ }
+
+ public static IEnumerable<object[]> GetHashCodeOrdinalIgnoreCase_TestData()
+ {
+ // 0 through 8 char lowercase & uppercase ASCII strings
+ // tests the various branches within the hash code calculation routines
+
+ for (int i = 0; i <= 8; i++)
+ {
+ yield return new object[] { "abcdefgh".Substring(0, i) };
+ yield return new object[] { "ABCDEFGH".Substring(0, i) };
+ }
+
+ // 16 char mixed case mostly-ASCII string plus one non-ASCII character inserted at various locations
+ // tests fallback logic for OrdinalIgnoreCase hash
+
+ for (int i = 0; i <= 16; i++)
+ {
+ yield return new object[] { "AaBbCcDdEeFfGgHh".Insert(i, "\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */) };
+ yield return new object[] { "AaBbCcDdEeFfGgHh".Insert(i, "\u044D" /* CYRILLIC SMALL LETTER E */) };
+ yield return new object[] { "AaBbCcDdEeFfGgHh".Insert(i, "\u0131" /* LATIN SMALL LETTER DOTLESS I */) };
+ }
+
+ // Various texts copied from Microsoft's non-U.S. home pages, for further localization tests
+
+ yield return new object[] { "\u0418\u0433\u0440\u044B \u0438 \u0440\u0430\u0437\u0432\u043B\u0435\u0447\u0435\u043D\u0438\u044F \u0431\u0435\u0437 \u0433\u0440\u0430\u043D\u0438\u0446 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 4K." }; // ru-RU
+ yield return new object[] { "Poder port\u00E1til." }; // es-ES
+ yield return new object[] { "\u60F3\u50CF\u3092\u8D85\u3048\u305F\u3001\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\u3092\u3002" }; // ja-JP
+ yield return new object[] { "\u00C9l\u00E9gant et performant." }; // fr-FR
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class StringGetHashCodeTests
- {
- [Theory]
- [MemberData(nameof(GetHashCodeOrdinalIgnoreCase_TestData))]
- public void GetHashCode_OrdinalIgnoreCase_ReturnsSameHashCodeAsUpperCaseOrdinal(string input)
- {
- // As an implementation detail, the OrdinalIgnoreCase hash code calculation is simply the hash code
- // of the upper-invariant version of the input string.
-
- Assert.Equal(input.ToUpperInvariant().GetHashCode(), input.GetHashCode(StringComparison.OrdinalIgnoreCase));
- }
-
- public static IEnumerable<object[]> GetHashCodeOrdinalIgnoreCase_TestData()
- {
- // 0 through 8 char lowercase & uppercase ASCII strings
- // tests the various branches within the hash code calculation routines
-
- for (int i = 0; i <= 8; i++)
- {
- yield return new object[] { "abcdefgh".Substring(0, i) };
- yield return new object[] { "ABCDEFGH".Substring(0, i) };
- }
-
- // 16 char mixed case mostly-ASCII string plus one non-ASCII character inserted at various locations
- // tests fallback logic for OrdinalIgnoreCase hash
-
- for (int i = 0; i <= 16; i++)
- {
- yield return new object[] { "AaBbCcDdEeFfGgHh".Insert(i, "\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */) };
- yield return new object[] { "AaBbCcDdEeFfGgHh".Insert(i, "\u044D" /* CYRILLIC SMALL LETTER E */) };
- yield return new object[] { "AaBbCcDdEeFfGgHh".Insert(i, "\u0131" /* LATIN SMALL LETTER DOTLESS I */) };
- }
-
- // Various texts copied from Microsoft's non-U.S. home pages, for further localization tests
-
- yield return new object[] { "\u0418\u0433\u0440\u044B \u0438 \u0440\u0430\u0437\u0432\u043B\u0435\u0447\u0435\u043D\u0438\u044F \u0431\u0435\u0437 \u0433\u0440\u0430\u043D\u0438\u0446 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 4K." }; // ru-RU
- yield return new object[] { "Poder port\u00E1til." }; // es-ES
- yield return new object[] { "\u60F3\u50CF\u3092\u8D85\u3048\u305F\u3001\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\u3092\u3002" }; // ja-JP
- yield return new object[] { "\u00C9l\u00E9gant et performant." }; // fr-FR
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.DotNet.RemoteExecutor;
+using Xunit;
+
+namespace System.Tests
+{
+ public partial class StringTests
+ {
+ [Theory]
+ [InlineData(0, 0)]
+ [InlineData(3, 1)]
+ public static void Ctor_CharSpan_EmptyString(int length, int offset)
+ {
+ Assert.Same(string.Empty, new string(new ReadOnlySpan<char>(new char[length], offset, 0)));
+ }
+
+ [Fact]
+ public static unsafe void Ctor_CharSpan_Empty()
+ {
+ Assert.Same(string.Empty, new string((ReadOnlySpan<char>)null));
+ Assert.Same(string.Empty, new string(ReadOnlySpan<char>.Empty));
+ }
+
+ [Theory]
+ [InlineData(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\0' }, 0, 8, "abcdefgh")]
+ [InlineData(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\0', 'i', 'j', 'k' }, 0, 12, "abcdefgh\0ijk")]
+ [InlineData(new char[] { 'a', 'b', 'c' }, 0, 0, "")]
+ [InlineData(new char[] { 'a', 'b', 'c' }, 0, 1, "a")]
+ [InlineData(new char[] { 'a', 'b', 'c' }, 2, 1, "c")]
+ [InlineData(new char[] { '\u8001', '\u8002', '\ufffd', '\u1234', '\ud800', '\udfff' }, 0, 6, "\u8001\u8002\ufffd\u1234\ud800\udfff")]
+ public static void Ctor_CharSpan(char[] valueArray, int startIndex, int length, string expected)
+ {
+ var span = new ReadOnlySpan<char>(valueArray, startIndex, length);
+ Assert.Equal(expected, new string(span));
+ }
+
+ [Fact]
+ public static unsafe void Ctor_CharPtr_DoesNotAccessInvalidPage()
+ {
+ // Allocates a buffer of all 'x' followed by a null terminator,
+ // then attempts to create a string instance from this at various offsets.
+
+ const int MaxCharCount = 128;
+ using BoundedMemory<char> boundedMemory = BoundedMemory.Allocate<char>(MaxCharCount);
+ boundedMemory.Span.Fill('x');
+ boundedMemory.Span[MaxCharCount - 1] = '\0';
+ boundedMemory.MakeReadonly();
+
+ using MemoryHandle memoryHandle = boundedMemory.Memory.Pin();
+
+ for (int i = 0; i < MaxCharCount; i++)
+ {
+ string expectedString = new string('x', MaxCharCount - i - 1);
+ string actualString = new string((char*)memoryHandle.Pointer + i);
+ Assert.Equal(expectedString, actualString);
+ }
+ }
+
+ [ConditionalFact(nameof(IsSimpleActiveCodePage))]
+ public static unsafe void Ctor_SBytePtr_DoesNotAccessInvalidPage()
+ {
+ // Allocates a buffer of all ' ' followed by a null terminator,
+ // then attempts to create a string instance from this at various offsets.
+ // We use U+0020 SPACE instead of any other character because it lives
+ // at offset 0x20 across every supported code page.
+
+ const int MaxByteCount = 128;
+ using BoundedMemory<sbyte> boundedMemory = BoundedMemory.Allocate<sbyte>(MaxByteCount);
+ boundedMemory.Span.Fill((sbyte)' ');
+ boundedMemory.Span[MaxByteCount - 1] = (sbyte)'\0';
+ boundedMemory.MakeReadonly();
+
+ using MemoryHandle memoryHandle = boundedMemory.Memory.Pin();
+
+ for (int i = 0; i < MaxByteCount; i++)
+ {
+ string expectedString = new string(' ', MaxByteCount - i - 1);
+ string actualString = new string((sbyte*)memoryHandle.Pointer + i);
+ Assert.Equal(expectedString, actualString);
+ }
+ }
+
+ [Fact]
+ public static void Create_InvalidArguments_Throw()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("action", () => string.Create(-1, 0, null));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => string.Create(-1, 0, (span, state) => { }));
+ }
+
+ [Fact]
+ public static void Create_Length0_ReturnsEmptyString()
+ {
+ bool actionInvoked = false;
+ Assert.Same(string.Empty, string.Create(0, 0, (span, state) => actionInvoked = true));
+ Assert.False(actionInvoked);
+ }
+
+ [Fact]
+ public static void Create_NullState_Allowed()
+ {
+ string result = string.Create(1, (object)null, (span, state) =>
+ {
+ span[0] = 'a';
+ Assert.Null(state);
+ });
+ Assert.Equal("a", result);
+ }
+
+ [Fact]
+ public static void Create_ClearsMemory()
+ {
+ const int Length = 10;
+ string result = string.Create(Length, (object)null, (span, state) =>
+ {
+ for (int i = 0; i < span.Length; i++)
+ {
+ Assert.Equal('\0', span[i]);
+ }
+ });
+ Assert.Equal(new string('\0', Length), result);
+ }
+
+ [Theory]
+ [InlineData("a")]
+ [InlineData("this is a test")]
+ [InlineData("\0\u8001\u8002\ufffd\u1234\ud800\udfff")]
+ public static void Create_ReturnsExpectedString(string expected)
+ {
+ char[] input = expected.ToCharArray();
+ string result = string.Create(input.Length, input, (span, state) =>
+ {
+ Assert.Same(input, state);
+ for (int i = 0; i < state.Length; i++)
+ {
+ span[i] = state[i];
+ }
+ });
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [InlineData("Hello", 'H', true)]
+ [InlineData("Hello", 'Z', false)]
+ [InlineData("Hello", 'e', true)]
+ [InlineData("Hello", 'E', false)]
+ [InlineData("", 'H', false)]
+ public static void Contains(string s, char value, bool expected)
+ {
+ Assert.Equal(expected, s.Contains(value));
+
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(expected, span.Contains(value));
+ }
+
+ [Theory]
+ // CurrentCulture
+ [InlineData("Hello", 'H', StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", 'Z', StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", 'e', StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", 'E', StringComparison.CurrentCulture, false)]
+ [InlineData("", 'H', StringComparison.CurrentCulture, false)]
+ // CurrentCultureIgnoreCase
+ [InlineData("Hello", 'H', StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", 'Z', StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("Hello", 'e', StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", 'E', StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("", 'H', StringComparison.CurrentCultureIgnoreCase, false)]
+ // InvariantCulture
+ [InlineData("Hello", 'H', StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", 'Z', StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", 'e', StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", 'E', StringComparison.InvariantCulture, false)]
+ [InlineData("", 'H', StringComparison.InvariantCulture, false)]
+ // InvariantCultureIgnoreCase
+ [InlineData("Hello", 'H', StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", 'Z', StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("Hello", 'e', StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", 'E', StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("", 'H', StringComparison.InvariantCultureIgnoreCase, false)]
+ // Ordinal
+ [InlineData("Hello", 'H', StringComparison.Ordinal, true)]
+ [InlineData("Hello", 'Z', StringComparison.Ordinal, false)]
+ [InlineData("Hello", 'e', StringComparison.Ordinal, true)]
+ [InlineData("Hello", 'E', StringComparison.Ordinal, false)]
+ [InlineData("", 'H', StringComparison.Ordinal, false)]
+ // OrdinalIgnoreCase
+ [InlineData("Hello", 'H', StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", 'Z', StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", 'e', StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", 'E', StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("", 'H', StringComparison.OrdinalIgnoreCase, false)]
+ public static void Contains(string s, char value, StringComparison comparisionType, bool expected)
+ {
+ Assert.Equal(expected, s.Contains(value, comparisionType));
+ }
+
+ [Theory]
+ // CurrentCulture
+ [InlineData("Hello", "ello", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "ELL", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "ElLo", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "Larger Hello", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "Goodbye", StringComparison.CurrentCulture, false)]
+ [InlineData("", "", StringComparison.CurrentCulture, true)]
+ [InlineData("", "hello", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "ell" + SoftHyphen, StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.CurrentCulture, false)]
+ // CurrentCultureIgnoreCase
+ [InlineData("Hello", "ello", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "ELL", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "ElLo", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "Larger Hello", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("Hello", "Goodbye", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("", "", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("", "hello", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("Hello", "", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "ell" + SoftHyphen, StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.CurrentCultureIgnoreCase, true)]
+ // InvariantCulture
+ [InlineData("Hello", "ello", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "ELL", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "ElLo", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "Larger Hello", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "Goodbye", StringComparison.InvariantCulture, false)]
+ [InlineData("", "", StringComparison.InvariantCulture, true)]
+ [InlineData("", "hello", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "ell" + SoftHyphen, StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.InvariantCulture, false)]
+ // InvariantCultureIgnoreCase
+ [InlineData("Hello", "ello", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "ELL", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "ElLo", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "Larger Hello", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("Hello", "Goodbye", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("", "", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("", "hello", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("Hello", "", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "ell" + SoftHyphen, StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.InvariantCultureIgnoreCase, true)]
+ // Ordinal
+ [InlineData("Hello", "ello", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "ELL", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "ElLo", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "Larger Hello", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "Goodbye", StringComparison.Ordinal, false)]
+ [InlineData("", "", StringComparison.Ordinal, true)]
+ [InlineData("", "hello", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "ell" + SoftHyphen, StringComparison.Ordinal, false)]
+ [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.Ordinal, false)]
+ // OrdinalIgnoreCase
+ [InlineData("Hello", "ello", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "ELL", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "ElLo", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Larger Hello", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "Goodbye", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("", "", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("", "hello", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "ell" + SoftHyphen, StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.OrdinalIgnoreCase, false)]
+ public static void Contains(string s, string value, StringComparison comparisonType, bool expected)
+ {
+ Assert.Equal(expected, s.Contains(value, comparisonType));
+ Assert.Equal(expected, s.AsSpan().Contains(value, comparisonType));
+ }
+
+ [Fact]
+ public static void Contains_StringComparison_TurkishI()
+ {
+ const string Source = "\u0069\u0130";
+
+ using (new ThreadCultureChange("tr-TR"))
+ {
+ Assert.True(Source.Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(Source.AsSpan().Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
+ }
+
+ using (new ThreadCultureChange("en-US"))
+ {
+ Assert.False(Source.Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
+ Assert.False(Source.AsSpan().Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void Contains_Match_Char()
+ {
+ Assert.False("".Contains('a'));
+ Assert.False("".AsSpan().Contains('a'));
+
+ // Use a long-enough string to incur vectorization code
+ const int max = 250;
+
+ for (var length = 1; length < max; length++)
+ {
+ char[] ca = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ ca[i] = (char)(i + 1);
+ }
+
+ var span = new Span<char>(ca);
+ var ros = new ReadOnlySpan<char>(ca);
+ var str = new string(ca);
+
+ for (var targetIndex = 0; targetIndex < length; targetIndex++)
+ {
+ char target = ca[targetIndex];
+
+ // Span
+ bool found = span.Contains(target);
+ Assert.True(found);
+
+ // ReadOnlySpan
+ found = ros.Contains(target);
+ Assert.True(found);
+
+ // String
+ found = str.Contains(target);
+ Assert.True(found);
+ }
+ }
+ }
+
+ [Fact]
+ public static void Contains_ZeroLength_Char()
+ {
+ // Span
+ var span = new Span<char>(Array.Empty<char>());
+ bool found = span.Contains((char)0);
+ Assert.False(found);
+
+ span = Span<char>.Empty;
+ found = span.Contains((char)0);
+ Assert.False(found);
+
+ // ReadOnlySpan
+ var ros = new ReadOnlySpan<char>(Array.Empty<char>());
+ found = ros.Contains((char)0);
+ Assert.False(found);
+
+ ros = ReadOnlySpan<char>.Empty;
+ found = ros.Contains((char)0);
+ Assert.False(found);
+
+ // String
+ found = string.Empty.Contains((char)0);
+ Assert.False(found);
+ }
+
+ [Fact]
+ public static void Contains_MultipleMatches_Char()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ var ca = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ ca[i] = (char)(i + 1);
+ }
+
+ ca[length - 1] = (char)200;
+ ca[length - 2] = (char)200;
+
+ // Span
+ var span = new Span<char>(ca);
+ bool found = span.Contains((char)200);
+ Assert.True(found);
+
+ // ReadOnlySpan
+ var ros = new ReadOnlySpan<char>(ca);
+ found = ros.Contains((char)200);
+ Assert.True(found);
+
+ // String
+ var str = new string(ca);
+ found = str.Contains((char)200);
+ Assert.True(found);
+ }
+ }
+
+ [Fact]
+ public static void Contains_EnsureNoChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var ca = new char[length + 2];
+ ca[0] = '9';
+ ca[length + 1] = '9';
+
+ // Span
+ var span = new Span<char>(ca, 1, length);
+ bool found = span.Contains('9');
+ Assert.False(found);
+
+ // ReadOnlySpan
+ var ros = new ReadOnlySpan<char>(ca, 1, length);
+ found = ros.Contains('9');
+ Assert.False(found);
+
+ // String
+ var str = new string(ca, 1, length);
+ found = str.Contains('9');
+ Assert.False(found);
+ }
+ }
+
+ [Theory]
+ [InlineData(StringComparison.CurrentCulture)]
+ [InlineData(StringComparison.CurrentCultureIgnoreCase)]
+ [InlineData(StringComparison.InvariantCulture)]
+ [InlineData(StringComparison.InvariantCultureIgnoreCase)]
+ [InlineData(StringComparison.Ordinal)]
+ [InlineData(StringComparison.OrdinalIgnoreCase)]
+ public static void Contains_NullValue_ThrowsArgumentNullException(StringComparison comparisonType)
+ {
+ AssertExtensions.Throws<ArgumentNullException>("value", () => "foo".Contains(null, comparisonType));
+ }
+
+ [Theory]
+ [InlineData(StringComparison.CurrentCulture - 1)]
+ [InlineData(StringComparison.OrdinalIgnoreCase + 1)]
+ public static void Contains_InvalidComparisonType_ThrowsArgumentOutOfRangeException(StringComparison comparisonType)
+ {
+ AssertExtensions.Throws<ArgumentException>("comparisonType", () => "ab".Contains("a", comparisonType));
+ }
+
+ [Theory]
+ [InlineData("Hello", 'o', true)]
+ [InlineData("Hello", 'O', false)]
+ [InlineData("o", 'o', true)]
+ [InlineData("o", 'O', false)]
+ [InlineData("Hello", 'e', false)]
+ [InlineData("Hello", '\0', false)]
+ [InlineData("", '\0', false)]
+ [InlineData("\0", '\0', true)]
+ [InlineData("", 'a', false)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", 'z', true)]
+ public static void EndsWith(string s, char value, bool expected)
+ {
+ Assert.Equal(expected, s.EndsWith(value));
+ }
+
+ [Theory]
+ [InlineData(new char[0], new int[0])] // empty
+ [InlineData(new char[] { 'x', 'y', 'z' }, new int[] { 'x', 'y', 'z' })]
+ [InlineData(new char[] { 'x', '\uD86D', '\uDF54', 'y' }, new int[] { 'x', 0x2B754, 'y' })] // valid surrogate pair
+ [InlineData(new char[] { 'x', '\uD86D', 'y' }, new int[] { 'x', 0xFFFD, 'y' })] // standalone high surrogate
+ [InlineData(new char[] { 'x', '\uDF54', 'y' }, new int[] { 'x', 0xFFFD, 'y' })] // standalone low surrogate
+ [InlineData(new char[] { 'x', '\uD86D' }, new int[] { 'x', 0xFFFD })] // standalone high surrogate at end of string
+ [InlineData(new char[] { 'x', '\uDF54' }, new int[] { 'x', 0xFFFD })] // standalone low surrogate at end of string
+ [InlineData(new char[] { 'x', '\uD86D', '\uD86D', 'y' }, new int[] { 'x', 0xFFFD, 0xFFFD, 'y' })] // two high surrogates should be two replacement chars
+ [InlineData(new char[] { 'x', '\uFFFD', 'y' }, new int[] { 'x', 0xFFFD, 'y' })] // literal U+FFFD
+ public static void EnumerateRunes(char[] chars, int[] expected)
+ {
+ // Test data is smuggled as char[] instead of straight-up string since the test framework
+ // doesn't like invalid UTF-16 literals.
+
+ string asString = new string(chars);
+
+ // First, use a straight-up foreach keyword to ensure pattern matching works as expected
+
+ List<int> enumeratedScalarValues = new List<int>();
+ foreach (Rune rune in asString.EnumerateRunes())
+ {
+ enumeratedScalarValues.Add(rune.Value);
+ }
+ Assert.Equal(expected, enumeratedScalarValues.ToArray());
+
+ // Then use LINQ to ensure IEnumerator<...> works as expected
+
+ int[] enumeratedValues = new string(chars).EnumerateRunes().Select(r => r.Value).ToArray();
+ Assert.Equal(expected, enumeratedValues);
+ }
+
+ [Theory]
+ [InlineData("Hello", 'H', true)]
+ [InlineData("Hello", 'h', false)]
+ [InlineData("H", 'H', true)]
+ [InlineData("H", 'h', false)]
+ [InlineData("Hello", 'e', false)]
+ [InlineData("Hello", '\0', false)]
+ [InlineData("", '\0', false)]
+ [InlineData("\0", '\0', true)]
+ [InlineData("", 'a', false)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", 'a', true)]
+ public static void StartsWith(string s, char value, bool expected)
+ {
+ Assert.Equal(expected, s.StartsWith(value));
+ }
+
+ public static IEnumerable<object[]> Join_Char_StringArray_TestData()
+ {
+ yield return new object[] { '|', new string[0], 0, 0, "" };
+ yield return new object[] { '|', new string[] { "a" }, 0, 1, "a" };
+ yield return new object[] { '|', new string[] { "a", "b", "c" }, 0, 3, "a|b|c" };
+ yield return new object[] { '|', new string[] { "a", "b", "c" }, 0, 2, "a|b" };
+ yield return new object[] { '|', new string[] { "a", "b", "c" }, 1, 1, "b" };
+ yield return new object[] { '|', new string[] { "a", "b", "c" }, 1, 2, "b|c" };
+ yield return new object[] { '|', new string[] { "a", "b", "c" }, 3, 0, "" };
+ yield return new object[] { '|', new string[] { "a", "b", "c" }, 0, 0, "" };
+ yield return new object[] { '|', new string[] { "", "", "" }, 0, 3, "||" };
+ yield return new object[] { '|', new string[] { null, null, null }, 0, 3, "||" };
+ }
+
+ [Theory]
+ [MemberData(nameof(Join_Char_StringArray_TestData))]
+ public static void Join_Char_StringArray(char separator, string[] values, int startIndex, int count, string expected)
+ {
+ if (startIndex == 0 && count == values.Length)
+ {
+ Assert.Equal(expected, string.Join(separator, values));
+ Assert.Equal(expected, string.Join(separator, (IEnumerable<string>)values));
+ Assert.Equal(expected, string.Join(separator, (object[])values));
+ Assert.Equal(expected, string.Join(separator, (IEnumerable<object>)values));
+ }
+
+ Assert.Equal(expected, string.Join(separator, values, startIndex, count));
+ Assert.Equal(expected, string.Join(separator.ToString(), values, startIndex, count));
+ }
+
+ public static IEnumerable<object[]> Join_Char_ObjectArray_TestData()
+ {
+ yield return new object[] { '|', new object[0], "" };
+ yield return new object[] { '|', new object[] { 1 }, "1" };
+ yield return new object[] { '|', new object[] { 1, 2, 3 }, "1|2|3" };
+ yield return new object[] { '|', new object[] { new ObjectWithNullToString(), 2, new ObjectWithNullToString() }, "|2|" };
+ yield return new object[] { '|', new object[] { "1", null, "3" }, "1||3" };
+ yield return new object[] { '|', new object[] { "", "", "" }, "||" };
+ yield return new object[] { '|', new object[] { "", null, "" }, "||" };
+ yield return new object[] { '|', new object[] { null, null, null }, "||" };
+ }
+
+ [Theory]
+ [MemberData(nameof(Join_Char_ObjectArray_TestData))]
+ public static void Join_Char_ObjectArray(char separator, object[] values, string expected)
+ {
+ Assert.Equal(expected, string.Join(separator, values));
+ Assert.Equal(expected, string.Join(separator, (IEnumerable<object>)values));
+ }
+
+ [Fact]
+ public static void Join_Char_NullValues_ThrowsArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("value", () => string.Join('|', (string[])null));
+ AssertExtensions.Throws<ArgumentNullException>("value", () => string.Join('|', (string[])null, 0, 0));
+ AssertExtensions.Throws<ArgumentNullException>("values", () => string.Join('|', (object[])null));
+ AssertExtensions.Throws<ArgumentNullException>("values", () => string.Join('|', (IEnumerable<object>)null));
+ }
+
+ [Fact]
+ public static void Join_Char_NegativeStartIndex_ThrowsArgumentOutOfRangeException()
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("startIndex", () => string.Join('|', new string[] { "Foo" }, -1, 0));
+ }
+
+ [Fact]
+ public static void Join_Char_NegativeCount_ThrowsArgumentOutOfRangeException()
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => string.Join('|', new string[] { "Foo" }, 0, -1));
+ }
+
+ [Theory]
+ [InlineData(2, 1)]
+ [InlineData(2, 0)]
+ [InlineData(1, 2)]
+ [InlineData(1, 1)]
+ [InlineData(0, 2)]
+ [InlineData(-1, 0)]
+ public static void Join_Char_InvalidStartIndexCount_ThrowsArgumentOutOfRangeException(int startIndex, int count)
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("startIndex", () => string.Join('|', new string[] { "Foo" }, startIndex, count));
+ }
+
+ public static IEnumerable<object[]> Replace_StringComparison_TestData()
+ {
+ yield return new object[] { "abc", "abc", "def", StringComparison.CurrentCulture, "def" };
+ yield return new object[] { "abc", "ABC", "def", StringComparison.CurrentCulture, "abc" };
+ yield return new object[] { "abc", "abc", "", StringComparison.CurrentCulture, "" };
+ yield return new object[] { "abc", "b", "LONG", StringComparison.CurrentCulture, "aLONGc" };
+ yield return new object[] { "abc", "b", "d", StringComparison.CurrentCulture, "adc" };
+ yield return new object[] { "abc", "b", null, StringComparison.CurrentCulture, "ac" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.CurrentCulture, "def" };
+
+ yield return new object[] { "abc", "abc", "def", StringComparison.CurrentCultureIgnoreCase, "def" };
+ yield return new object[] { "abc", "ABC", "def", StringComparison.CurrentCultureIgnoreCase, "def" };
+ yield return new object[] { "abc", "abc", "", StringComparison.CurrentCultureIgnoreCase, "" };
+ yield return new object[] { "abc", "b", "LONG", StringComparison.CurrentCultureIgnoreCase, "aLONGc" };
+ yield return new object[] { "abc", "b", "d", StringComparison.CurrentCultureIgnoreCase, "adc" };
+ yield return new object[] { "abc", "b", null, StringComparison.CurrentCultureIgnoreCase, "ac" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.CurrentCultureIgnoreCase, "def" };
+
+ yield return new object[] { "abc", "abc", "def", StringComparison.Ordinal, "def" };
+ yield return new object[] { "abc", "ABC", "def", StringComparison.Ordinal, "abc" };
+ yield return new object[] { "abc", "abc", "", StringComparison.Ordinal, "" };
+ yield return new object[] { "abc", "b", "LONG", StringComparison.Ordinal, "aLONGc" };
+ yield return new object[] { "abc", "b", "d", StringComparison.Ordinal, "adc" };
+ yield return new object[] { "abc", "b", null, StringComparison.Ordinal, "ac" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.Ordinal, "abc" };
+
+ yield return new object[] { "abc", "abc", "def", StringComparison.OrdinalIgnoreCase, "def" };
+ yield return new object[] { "abc", "ABC", "def", StringComparison.OrdinalIgnoreCase, "def" };
+ yield return new object[] { "abc", "abc", "", StringComparison.OrdinalIgnoreCase, "" };
+ yield return new object[] { "abc", "b", "LONG", StringComparison.OrdinalIgnoreCase, "aLONGc" };
+ yield return new object[] { "abc", "b", "d", StringComparison.OrdinalIgnoreCase, "adc" };
+ yield return new object[] { "abc", "b", null, StringComparison.OrdinalIgnoreCase, "ac" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.OrdinalIgnoreCase, "abc" };
+
+ yield return new object[] { "abc", "abc", "def", StringComparison.InvariantCulture, "def" };
+ yield return new object[] { "abc", "ABC", "def", StringComparison.InvariantCulture, "abc" };
+ yield return new object[] { "abc", "abc", "", StringComparison.InvariantCulture, "" };
+ yield return new object[] { "abc", "b", "LONG", StringComparison.InvariantCulture, "aLONGc" };
+ yield return new object[] { "abc", "b", "d", StringComparison.InvariantCulture, "adc" };
+ yield return new object[] { "abc", "b", null, StringComparison.InvariantCulture, "ac" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.InvariantCulture, "def" };
+
+ yield return new object[] { "abc", "abc", "def", StringComparison.InvariantCultureIgnoreCase, "def" };
+ yield return new object[] { "abc", "ABC", "def", StringComparison.InvariantCultureIgnoreCase, "def" };
+ yield return new object[] { "abc", "abc", "", StringComparison.InvariantCultureIgnoreCase, "" };
+ yield return new object[] { "abc", "b", "LONG", StringComparison.InvariantCultureIgnoreCase, "aLONGc" };
+ yield return new object[] { "abc", "b", "d", StringComparison.InvariantCultureIgnoreCase, "adc" };
+ yield return new object[] { "abc", "b", null, StringComparison.InvariantCultureIgnoreCase, "ac" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.InvariantCultureIgnoreCase, "def" };
+
+ string turkishSource = "\u0069\u0130";
+
+ yield return new object[] { turkishSource, "\u0069", "a", StringComparison.Ordinal, "a\u0130" };
+ yield return new object[] { turkishSource, "\u0069", "a", StringComparison.OrdinalIgnoreCase, "a\u0130" };
+ yield return new object[] { turkishSource, "\u0130", "a", StringComparison.Ordinal, "\u0069a" };
+ yield return new object[] { turkishSource, "\u0130", "a", StringComparison.OrdinalIgnoreCase, "\u0069a" };
+
+ yield return new object[] { turkishSource, "\u0069", "a", StringComparison.InvariantCulture, "a\u0130" };
+ yield return new object[] { turkishSource, "\u0069", "a", StringComparison.InvariantCultureIgnoreCase, "a\u0130" };
+ yield return new object[] { turkishSource, "\u0130", "a", StringComparison.InvariantCulture, "\u0069a" };
+ yield return new object[] { turkishSource, "\u0130", "a", StringComparison.InvariantCultureIgnoreCase, "\u0069a" };
+ }
+
+ [Theory]
+ [MemberData(nameof(Replace_StringComparison_TestData))]
+ public void Replace_StringComparison_ReturnsExpected(string original, string oldValue, string newValue, StringComparison comparisonType, string expected)
+ {
+ Assert.Equal(expected, original.Replace(oldValue, newValue, comparisonType));
+ }
+
+ [Fact]
+ public void Replace_StringComparison_TurkishI()
+ {
+ const string Source = "\u0069\u0130";
+
+ using (new ThreadCultureChange("tr-TR"))
+ {
+ Assert.True("\u0069".Equals("\u0130", StringComparison.CurrentCultureIgnoreCase));
+
+ Assert.Equal("a\u0130", Source.Replace("\u0069", "a", StringComparison.CurrentCulture));
+ Assert.Equal("aa", Source.Replace("\u0069", "a", StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal("\u0069a", Source.Replace("\u0130", "a", StringComparison.CurrentCulture));
+ Assert.Equal("aa", Source.Replace("\u0130", "a", StringComparison.CurrentCultureIgnoreCase));
+ }
+
+ using (new ThreadCultureChange("en-US"))
+ {
+ Assert.False("\u0069".Equals("\u0130", StringComparison.CurrentCultureIgnoreCase));
+
+ Assert.Equal("a\u0130", Source.Replace("\u0069", "a", StringComparison.CurrentCulture));
+ Assert.Equal("a\u0130", Source.Replace("\u0069", "a", StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal("\u0069a", Source.Replace("\u0130", "a", StringComparison.CurrentCulture));
+ Assert.Equal("\u0069a", Source.Replace("\u0130", "a", StringComparison.CurrentCultureIgnoreCase));
+ }
+ }
+
+ public static IEnumerable<object[]> Replace_StringComparisonCulture_TestData()
+ {
+ yield return new object[] { "abc", "abc", "def", false, null, "def" };
+ yield return new object[] { "abc", "ABC", "def", false, null, "abc" };
+ yield return new object[] { "abc", "abc", "def", false, CultureInfo.InvariantCulture, "def" };
+ yield return new object[] { "abc", "ABC", "def", false, CultureInfo.InvariantCulture, "abc" };
+
+ yield return new object[] { "abc", "abc", "def", true, null, "def" };
+ yield return new object[] { "abc", "ABC", "def", true, null, "def" };
+ yield return new object[] { "abc", "abc", "def", true, CultureInfo.InvariantCulture, "def" };
+ yield return new object[] { "abc", "ABC", "def", true, CultureInfo.InvariantCulture, "def" };
+
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", false, null, "def" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", true, null, "def" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", false, CultureInfo.InvariantCulture, "def" };
+ yield return new object[] { "abc", "abc" + SoftHyphen, "def", true, CultureInfo.InvariantCulture, "def" };
+
+ yield return new object[] { "\u0069\u0130", "\u0069", "a", false, new CultureInfo("tr-TR"), "a\u0130" };
+ yield return new object[] { "\u0069\u0130", "\u0069", "a", true, new CultureInfo("tr-TR"), "aa" };
+ yield return new object[] { "\u0069\u0130", "\u0069", "a", false, CultureInfo.InvariantCulture, "a\u0130" };
+ yield return new object[] { "\u0069\u0130", "\u0069", "a", true, CultureInfo.InvariantCulture, "a\u0130" };
+ }
+
+ [Theory]
+ [MemberData(nameof(Replace_StringComparisonCulture_TestData))]
+ public void Replace_StringComparisonCulture_ReturnsExpected(string original, string oldValue, string newValue, bool ignoreCase, CultureInfo culture, string expected)
+ {
+ Assert.Equal(expected, original.Replace(oldValue, newValue, ignoreCase, culture));
+ if (culture == null)
+ {
+ Assert.Equal(expected, original.Replace(oldValue, newValue, ignoreCase, CultureInfo.CurrentCulture));
+ }
+ }
+
+ [Fact]
+ public void Replace_StringComparison_NullOldValue_ThrowsArgumentException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("oldValue", () => "abc".Replace(null, "def", StringComparison.CurrentCulture));
+ AssertExtensions.Throws<ArgumentNullException>("oldValue", () => "abc".Replace(null, "def", true, CultureInfo.CurrentCulture));
+ }
+
+ [Fact]
+ public void Replace_StringComparison_EmptyOldValue_ThrowsArgumentException()
+ {
+ AssertExtensions.Throws<ArgumentException>("oldValue", () => "abc".Replace("", "def", StringComparison.CurrentCulture));
+ AssertExtensions.Throws<ArgumentException>("oldValue", () => "abc".Replace("", "def", true, CultureInfo.CurrentCulture));
+ }
+
+ [Theory]
+ [InlineData(StringComparison.CurrentCulture - 1)]
+ [InlineData(StringComparison.OrdinalIgnoreCase + 1)]
+ public void Replace_NoSuchStringComparison_ThrowsArgumentException(StringComparison comparisonType)
+ {
+ AssertExtensions.Throws<ArgumentException>("comparisonType", () => "abc".Replace("abc", "def", comparisonType));
+ }
+
+
+ private static readonly StringComparison[] StringComparisons = (StringComparison[])Enum.GetValues(typeof(StringComparison));
+
+ [Fact]
+ public static void GetHashCode_OfSpan_EmbeddedNull_ReturnsDifferentHashCodes()
+ {
+ Assert.NotEqual(string.GetHashCode("\0AAAAAAAAA".AsSpan()), string.GetHashCode("\0BBBBBBBBBBBB".AsSpan()));
+ }
+
+ [Fact]
+ public static void GetHashCode_OfSpan_MatchesOfString()
+ {
+ // parameterless should be ordinal only
+ Assert.Equal("abc".GetHashCode(), string.GetHashCode("abc".AsSpan()));
+ Assert.NotEqual("abc".GetHashCode(), string.GetHashCode("ABC".AsSpan())); // case differences
+ }
+
+ [Fact]
+ public static void GetHashCode_CompareInfo()
+ {
+ // ordinal
+ Assert.Equal("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc", CompareOptions.Ordinal));
+ Assert.NotEqual("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC", CompareOptions.Ordinal));
+
+ // ordinal ignore case
+ Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc", CompareOptions.OrdinalIgnoreCase));
+ Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC", CompareOptions.OrdinalIgnoreCase));
+
+ // culture-aware
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCulture), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.None));
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCultureIgnoreCase), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.IgnoreCase));
+
+ // invariant culture
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCulture), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.None));
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCultureIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.IgnoreCase));
+ }
+
+ [Fact]
+ public static void GetHashCode_CompareInfo_OfSpan()
+ {
+ // ordinal
+ Assert.Equal("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc".AsSpan(), CompareOptions.Ordinal));
+ Assert.NotEqual("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC".AsSpan(), CompareOptions.Ordinal));
+
+ // ordinal ignore case
+ Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc".AsSpan(), CompareOptions.OrdinalIgnoreCase));
+ Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC".AsSpan(), CompareOptions.OrdinalIgnoreCase));
+
+ // culture-aware
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCulture), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.None));
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCultureIgnoreCase), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.IgnoreCase));
+
+ // invariant culture
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCulture), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.None));
+ Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCultureIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.IgnoreCase));
+ }
+
+ public static IEnumerable<object[]> GetHashCode_StringComparison_Data => StringComparisons.Select(value => new object[] { value });
+
+ [Theory]
+ [MemberData(nameof(GetHashCode_StringComparison_Data))]
+ public static void GetHashCode_StringComparison(StringComparison comparisonType)
+ {
+ int hashCodeFromStringComparer = StringComparer.FromComparison(comparisonType).GetHashCode("abc");
+ int hashCodeFromStringGetHashCode = "abc".GetHashCode(comparisonType);
+ int hashCodeFromStringGetHashCodeOfSpan = string.GetHashCode("abc".AsSpan(), comparisonType);
+
+ Assert.Equal(hashCodeFromStringComparer, hashCodeFromStringGetHashCode);
+ Assert.Equal(hashCodeFromStringComparer, hashCodeFromStringGetHashCodeOfSpan);
+ }
+
+ public static IEnumerable<object[]> GetHashCode_NoSuchStringComparison_ThrowsArgumentException_Data => new[]
+ {
+ new object[] { StringComparisons.Min() - 1 },
+ new object[] { StringComparisons.Max() + 1 },
+ };
+
+ [Theory]
+ [MemberData(nameof(GetHashCode_NoSuchStringComparison_ThrowsArgumentException_Data))]
+ public static void GetHashCode_NoSuchStringComparison_ThrowsArgumentException(StringComparison comparisonType)
+ {
+ AssertExtensions.Throws<ArgumentException>("comparisonType", () => "abc".GetHashCode(comparisonType));
+ AssertExtensions.Throws<ArgumentException>("comparisonType", () => string.GetHashCode("abc".AsSpan(), comparisonType));
+ }
+
+ [Theory]
+ [InlineData("")] // empty string
+ [InlineData("hello")] // non-empty string
+ public static unsafe void GetPinnableReference_ReturnsSameAsGCHandleAndLegacyFixed(string input)
+ {
+ Assert.NotNull(input); // test shouldn't have null input
+
+ // First, ensure the value pointed to by GetPinnableReference is correct.
+ // It should point to the first character (or the null terminator for empty inputs).
+
+ ref readonly char rChar = ref input.GetPinnableReference();
+ Assert.Equal((input.Length > 0) ? input[0] : '\0', rChar);
+
+ // Next, ensure that GetPinnableReference() and GCHandle.AddrOfPinnedObject agree
+ // on the address being returned.
+
+ GCHandle gcHandle = GCHandle.Alloc(input, GCHandleType.Pinned);
+ try
+ {
+ Assert.Equal((IntPtr)Unsafe.AsPointer(ref Unsafe.AsRef(in rChar)), gcHandle.AddrOfPinnedObject());
+ }
+ finally
+ {
+ gcHandle.Free();
+ }
+
+ // Next, ensure that GetPinnableReference matches the string projected as a ROS<char>.
+
+ Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in rChar), ref MemoryMarshal.GetReference((ReadOnlySpan<char>)input)));
+
+ // Finally, ensure that GetPinnableReference matches the legacy 'fixed' keyword.
+
+ DynamicMethod dynamicMethod = new DynamicMethod("tester", typeof(bool), new[] { typeof(string) });
+ ILGenerator ilGen = dynamicMethod.GetILGenerator();
+ LocalBuilder pinnedLocal = ilGen.DeclareLocal(typeof(object), pinned: true);
+
+ ilGen.Emit(OpCodes.Ldarg_0); // load 'input' and pin it
+ ilGen.Emit(OpCodes.Stloc, pinnedLocal);
+
+ ilGen.Emit(OpCodes.Ldloc, pinnedLocal); // get the address of field 0 from pinned 'input'
+ ilGen.Emit(OpCodes.Conv_I);
+
+ ilGen.Emit(OpCodes.Call, typeof(RuntimeHelpers).GetProperty("OffsetToStringData").GetMethod); // get pointer to start of string data
+ ilGen.Emit(OpCodes.Add);
+
+ ilGen.Emit(OpCodes.Ldarg_0); // get value of input.GetPinnableReference()
+ ilGen.Emit(OpCodes.Callvirt, typeof(string).GetMethod("GetPinnableReference"));
+
+ // At this point, the top of the evaluation stack is traditional (fixed char* = input) and input.GetPinnableReference().
+ // Compare for equality and return.
+
+ ilGen.Emit(OpCodes.Ceq);
+ ilGen.Emit(OpCodes.Ret);
+
+ Assert.True((bool)dynamicMethod.Invoke(null, new[] { input }));
+ }
+
+ [Fact]
+ public static unsafe void GetPinnableReference_WithNullInput_ThrowsNullRef()
+ {
+ // This test uses an explicit call instead of the normal callvirt that C# would emit.
+ // This allows us to make sure the NullReferenceException is coming from *within*
+ // the GetPinnableReference method rather than on the call site to that method.
+
+ DynamicMethod dynamicMethod = new DynamicMethod("tester", typeof(void), Type.EmptyTypes);
+ ILGenerator ilGen = dynamicMethod.GetILGenerator();
+
+ ilGen.Emit(OpCodes.Ldnull);
+ ilGen.Emit(OpCodes.Call, typeof(string).GetMethod("GetPinnableReference"));
+ ilGen.Emit(OpCodes.Pop);
+ ilGen.Emit(OpCodes.Ret);
+
+ Action del = (Action)dynamicMethod.CreateDelegate(typeof(Action));
+
+ Assert.NotNull(del);
+ Assert.Throws<NullReferenceException>(del);
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData("a")]
+ [InlineData("\0")]
+ [InlineData("abc")]
+ public static unsafe void ImplicitCast_ResultingSpanMatches(string s)
+ {
+ ReadOnlySpan<char> span = s;
+ Assert.Equal(s.Length, span.Length);
+ fixed (char* stringPtr = s)
+ fixed (char* spanPtr = &MemoryMarshal.GetReference(span))
+ {
+ Assert.Equal((IntPtr)stringPtr, (IntPtr)spanPtr);
+ }
+ }
+
+ [Fact]
+ public static void ImplicitCast_NullString_ReturnsDefaultSpan()
+ {
+ ReadOnlySpan<char> span = (string)null;
+ Assert.True(span == default);
+ }
+
+ [Theory]
+ [InlineData("Hello", 'l', StringComparison.Ordinal, 2)]
+ [InlineData("Hello", 'x', StringComparison.Ordinal, -1)]
+ [InlineData("Hello", 'h', StringComparison.Ordinal, -1)]
+ [InlineData("Hello", 'o', StringComparison.Ordinal, 4)]
+ [InlineData("Hello", 'h', StringComparison.OrdinalIgnoreCase, 0)]
+ [InlineData("HelLo", 'L', StringComparison.OrdinalIgnoreCase, 2)]
+ [InlineData("HelLo", 'L', StringComparison.Ordinal, 3)]
+ [InlineData("HelLo", '\0', StringComparison.Ordinal, -1)]
+ [InlineData("!@#$%", '%', StringComparison.Ordinal, 4)]
+ [InlineData("!@#$", '!', StringComparison.Ordinal, 0)]
+ [InlineData("!@#$", '@', StringComparison.Ordinal, 1)]
+ [InlineData("!@#$%", '%', StringComparison.OrdinalIgnoreCase, 4)]
+ [InlineData("!@#$", '!', StringComparison.OrdinalIgnoreCase, 0)]
+ [InlineData("!@#$", '@', StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("_____________\u807f", '\u007f', StringComparison.Ordinal, -1)]
+ [InlineData("_____________\u807f__", '\u007f', StringComparison.Ordinal, -1)]
+ [InlineData("_____________\u807f\u007f_", '\u007f', StringComparison.Ordinal, 14)]
+ [InlineData("__\u807f_______________", '\u007f', StringComparison.Ordinal, -1)]
+ [InlineData("__\u807f___\u007f___________", '\u007f', StringComparison.Ordinal, 6)]
+ [InlineData("_____________\u807f", '\u007f', StringComparison.OrdinalIgnoreCase, -1)]
+ [InlineData("_____________\u807f__", '\u007f', StringComparison.OrdinalIgnoreCase, -1)]
+ [InlineData("_____________\u807f\u007f_", '\u007f', StringComparison.OrdinalIgnoreCase, 14)]
+ [InlineData("__\u807f_______________", '\u007f', StringComparison.OrdinalIgnoreCase, -1)]
+ [InlineData("__\u807f___\u007f___________", '\u007f', StringComparison.OrdinalIgnoreCase, 6)]
+ public static void IndexOf_SingleLetter(string s, char target, StringComparison stringComparison, int expected)
+ {
+ Assert.Equal(expected, s.IndexOf(target, stringComparison));
+ var charArray = new char[1];
+ charArray[0] = target;
+ Assert.Equal(expected, s.AsSpan().IndexOf(charArray, stringComparison));
+ }
+
+ [Fact]
+ public static void IndexOf_TurkishI_TurkishCulture_Char()
+ {
+ using (new ThreadCultureChange("tr-TR"))
+ {
+ string s = "Turkish I \u0131s TROUBL\u0130NG!";
+ char value = '\u0130';
+ Assert.Equal(19, s.IndexOf(value));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(4, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.CurrentCulture));
+ Assert.Equal(4, span.IndexOf(new char[] { value }, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.Ordinal));
+ Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.OrdinalIgnoreCase));
+
+ value = '\u0131';
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.CurrentCulture));
+ Assert.Equal(8, span.IndexOf(new char[] { value }, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.Ordinal));
+ Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_TurkishI_InvariantCulture_Char()
+ {
+ using (new ThreadCultureChange(CultureInfo.InvariantCulture))
+ {
+ string s = "Turkish I \u0131s TROUBL\u0130NG!";
+ char value = '\u0130';
+
+ Assert.Equal(19, s.IndexOf(value));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ value = '\u0131';
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_TurkishI_EnglishUSCulture_Char()
+ {
+ using (new ThreadCultureChange("en-US"))
+ {
+ string s = "Turkish I \u0131s TROUBL\u0130NG!";
+ char value = '\u0130';
+
+ Assert.Equal(19, s.IndexOf(value));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ value = '\u0131';
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_EquivalentDiacritics_EnglishUSCulture_Char()
+ {
+ string s = "Exhibit a\u0300\u00C0";
+ char value = '\u00C0';
+
+ using (new ThreadCultureChange("en-US"))
+ {
+ Assert.Equal(10, s.IndexOf(value));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_EquivalentDiacritics_InvariantCulture_Char()
+ {
+ string s = "Exhibit a\u0300\u00C0";
+ char value = '\u00C0';
+
+ using (new ThreadCultureChange(CultureInfo.InvariantCulture))
+ {
+ Assert.Equal(10, s.IndexOf(value));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_CyrillicE_EnglishUSCulture_Char()
+ {
+ string s = "Foo\u0400Bar";
+ char value = '\u0400';
+
+ using (new ThreadCultureChange("en-US"))
+ {
+ Assert.Equal(3, s.IndexOf(value));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_CyrillicE_InvariantCulture_Char()
+ {
+ string s = "Foo\u0400Bar";
+ char value = '\u0400';
+
+ using (new ThreadCultureChange(CultureInfo.InvariantCulture))
+ {
+ Assert.Equal(3, s.IndexOf(value));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_Invalid_Char()
+ {
+ // Invalid comparison type
+ AssertExtensions.Throws<ArgumentException>("comparisonType", () => "foo".IndexOf('o', StringComparison.CurrentCulture - 1));
+ AssertExtensions.Throws<ArgumentException>("comparisonType", () => "foo".IndexOf('o', StringComparison.OrdinalIgnoreCase + 1));
+ }
+
+ [Theory]
+ [MemberData(nameof(Concat_Strings_2_3_4_TestData))]
+ public static void Concat_Spans(string[] values, string expected)
+ {
+ Assert.InRange(values.Length, 2, 4);
+
+ string result =
+ values.Length == 2 ? string.Concat(values[0].AsSpan(), values[1].AsSpan()) :
+ values.Length == 3 ? string.Concat(values[0].AsSpan(), values[1].AsSpan(), values[2].AsSpan()) :
+ string.Concat(values[0].AsSpan(), values[1].AsSpan(), values[2].AsSpan(), values[3].AsSpan());
+
+ if (result.Length == 0)
+ {
+ Assert.Same(string.Empty, result);
+ }
+
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public static void IndexerUsingIndexTest()
+ {
+ Index index;
+ string s = "0123456789ABCDEF";
+
+ for (int i = 0; i < s.Length; i++)
+ {
+ index = Index.FromStart(i);
+ Assert.Equal(s[i], s[index]);
+
+ index = Index.FromEnd(i + 1);
+ Assert.Equal(s[s.Length - i - 1], s[index]);
+ }
+
+ index = Index.FromStart(s.Length + 1);
+ char c;
+ Assert.Throws<IndexOutOfRangeException>(() => c = s[index]);
+
+ index = Index.FromEnd(s.Length + 1);
+ Assert.Throws<IndexOutOfRangeException>(() => c = s[index]);
+ }
+
+ [Fact]
+ public static void IndexerUsingRangeTest()
+ {
+ Range range;
+ string s = "0123456789ABCDEF";
+
+ for (int i = 0; i < s.Length; i++)
+ {
+ range = new Range(Index.FromStart(0), Index.FromStart(i));
+ Assert.Equal(s.Substring(0, i), s[range]);
+
+ range = new Range(Index.FromEnd(s.Length), Index.FromEnd(i));
+ Assert.Equal(s.Substring(0, s.Length - i), s[range]);
+ }
+
+ range = new Range(Index.FromStart(s.Length - 2), Index.FromStart(s.Length + 1));
+ string s1;
+ Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
+
+ range = new Range(Index.FromEnd(s.Length + 1), Index.FromEnd(0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
+ }
+
+ [Fact]
+ public static void SubstringUsingIndexTest()
+ {
+ string s = "0123456789ABCDEF";
+
+ for (int i = 0; i < s.Length; i++)
+ {
+ Assert.Equal(s.Substring(i), s[i..]);
+ Assert.Equal(s.Substring(s.Length - i - 1), s[^(i + 1)..]);
+ }
+
+ // String.Substring allows the string length as a valid input.
+ Assert.Equal(s.Substring(s.Length), s[s.Length..]);
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => s[(s.Length + 1)..]);
+ Assert.Throws<ArgumentOutOfRangeException>(() => s[^(s.Length + 1)..]);
+ }
+
+ [Fact]
+ public static void SubstringUsingRangeTest()
+ {
+ string s = "0123456789ABCDEF";
+ Range range;
+
+ for (int i = 0; i < s.Length; i++)
+ {
+ range = new Range(Index.FromStart(0), Index.FromStart(i));
+ Assert.Equal(s.Substring(0, i), s[range]);
+
+ range = new Range(Index.FromEnd(s.Length), Index.FromEnd(i));
+ Assert.Equal(s.Substring(0, s.Length - i), s[range]);
+ }
+
+ range = new Range(Index.FromStart(s.Length - 2), Index.FromStart(s.Length + 1));
+ string s1;
+ Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
+
+ range = new Range(Index.FromEnd(s.Length + 1), Index.FromEnd(0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
+ }
+
+ /// <summary>
+ /// Returns true only if U+0020 SPACE is represented as the single byte 0x20 in the active code page.
+ /// </summary>
+ public static unsafe bool IsSimpleActiveCodePage
+ {
+ get
+ {
+ IntPtr pAnsiStr = IntPtr.Zero;
+ try
+ {
+ pAnsiStr = Marshal.StringToHGlobalAnsi(" ");
+ return ((byte*)pAnsiStr)[0] == (byte)' ' && ((byte*)pAnsiStr)[1] == (byte)'\0';
+ }
+ finally
+ {
+ if (pAnsiStr != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(pAnsiStr);
+ }
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(" Hello ", "Hello")]
+ [InlineData(" \t ", "")]
+ [InlineData("", "")]
+ [InlineData(" ", "")]
+ public static void Trim_Memory(string s, string expected)
+ {
+ Assert.Equal(expected, s.AsSpan().Trim().ToString()); // ReadOnlySpan
+ Assert.Equal(expected, new Span<char>(s.ToCharArray()).Trim().ToString());
+ Assert.Equal(expected, new Memory<char>(s.ToCharArray()).Trim().ToString());
+ Assert.Equal(expected, s.AsMemory().Trim().ToString()); // ReadOnlyMemory
+ }
+
+ [Theory]
+ [InlineData(" Hello ", " Hello")]
+ [InlineData(" \t ", "")]
+ [InlineData("", "")]
+ [InlineData(" ", "")]
+ public static void TrimEnd_Memory(string s, string expected)
+ {
+ Assert.Equal(expected, s.AsSpan().TrimEnd().ToString()); // ReadOnlySpan
+ Assert.Equal(expected, new Span<char>(s.ToCharArray()).TrimEnd().ToString());
+ Assert.Equal(expected, new Memory<char>(s.ToCharArray()).TrimEnd().ToString());
+ Assert.Equal(expected, s.AsMemory().TrimEnd().ToString()); // ReadOnlyMemory
+ }
+
+ [Theory]
+ [InlineData(" Hello ", "Hello ")]
+ [InlineData(" \t ", "")]
+ [InlineData("", "")]
+ [InlineData(" ", "")]
+ public static void TrimStart_Memory(string s, string expected)
+ {
+ Assert.Equal(expected, s.AsSpan().TrimStart().ToString()); // ReadOnlySpan
+ Assert.Equal(expected, new Span<char>(s.ToCharArray()).TrimStart().ToString());
+ Assert.Equal(expected, new Memory<char>(s.ToCharArray()).TrimStart().ToString());
+ Assert.Equal(expected, s.AsMemory().TrimStart().ToString()); // ReadOnlyMemory
+ }
+
+ [Fact]
+ public static void ZeroLengthTrim_Memory()
+ {
+ string s1 = string.Empty;
+
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ Assert.True(ros.SequenceEqual(ros.Trim()));
+ Assert.True(ros.SequenceEqual(ros.TrimStart()));
+ Assert.True(ros.SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(s1.ToCharArray());
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(s1.ToCharArray());
+ Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(s1.ToCharArray());
+ Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+
+ [Fact]
+ public static void NoWhiteSpaceTrim_Memory()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ string s1 = new string(a);
+
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ Assert.True(ros.SequenceEqual(ros.Trim()));
+ Assert.True(ros.SequenceEqual(ros.TrimStart()));
+ Assert.True(ros.SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(a);
+ Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
+ Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+ }
+
+ [Fact]
+ public static void OnlyWhiteSpaceTrim_Memory()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = ' ';
+ }
+ string s1 = new string(a);
+
+ ReadOnlySpan<char> ros = new ReadOnlySpan<char>(a);
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(ros.Trim()));
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(ros.TrimStart()));
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(a);
+ Assert.True(Span<char>.Empty.SequenceEqual(span.Trim()));
+ Assert.True(Span<char>.Empty.SequenceEqual(span.TrimStart()));
+ Assert.True(Span<char>.Empty.SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(a);
+ Assert.True(Memory<char>.Empty.Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(Memory<char>.Empty.Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(Memory<char>.Empty.Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
+ Assert.True(ReadOnlyMemory<char>.Empty.Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(ReadOnlyMemory<char>.Empty.Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(ReadOnlyMemory<char>.Empty.Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceAtStartTrim_Memory()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[0] = ' ';
+ string s1 = new string(a);
+
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ Assert.True(ros.Slice(1).SequenceEqual(ros.Trim()));
+ Assert.True(ros.Slice(1).SequenceEqual(ros.TrimStart()));
+ Assert.True(ros.SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(a);
+ Assert.True(span.Slice(1).SequenceEqual(span.Trim()));
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(a);
+ Assert.True(mem.Slice(1).Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(mem.Slice(1).Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
+ Assert.True(rom.Slice(1).Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(rom.Slice(1).Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceAtEndTrim_Memory()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[length - 1] = ' ';
+ string s1 = new string(a);
+
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ Assert.True(ros.Slice(0, length - 1).SequenceEqual(ros.Trim()));
+ Assert.True(ros.SequenceEqual(ros.TrimStart()));
+ Assert.True(ros.Slice(0, length - 1).SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(a);
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(a);
+ Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
+ Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceAtStartAndEndTrim_Memory()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[0] = ' ';
+ a[length - 1] = ' ';
+ string s1 = new string(a);
+
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ Assert.True(ros.Slice(1, length - 2).SequenceEqual(ros.Trim()));
+ Assert.True(ros.Slice(1).SequenceEqual(ros.TrimStart()));
+ Assert.True(ros.Slice(0, length - 1).SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(a);
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(span.Trim()));
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart()));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(a);
+ Assert.True(mem.Slice(1, length - 2).Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(mem.Slice(1).Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
+ Assert.True(rom.Slice(1, length - 2).Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(rom.Slice(1).Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceInMiddleTrim_Memory()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[1] = ' ';
+ string s1 = new string(a);
+
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ Assert.True(ros.SequenceEqual(ros.Trim()));
+ Assert.True(ros.SequenceEqual(ros.TrimStart()));
+ Assert.True(ros.SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(a);
+ Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
+ Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+ }
+
+ [Fact]
+ public static void TrimWhiteSpaceMultipleTimes_Memory()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[0] = ' ';
+ a[length - 1] = ' ';
+ string s1 = new string(a);
+
+ // ReadOnlySpan
+ {
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ ReadOnlySpan<char> trimResult = ros.Trim();
+ ReadOnlySpan<char> trimStartResult = ros.TrimStart();
+ ReadOnlySpan<char> trimEndResult = ros.TrimEnd();
+ Assert.True(ros.Slice(1, length - 2).SequenceEqual(trimResult));
+ Assert.True(ros.Slice(1).SequenceEqual(trimStartResult));
+ Assert.True(ros.Slice(0, length - 1).SequenceEqual(trimEndResult));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimResult.SequenceEqual(trimResult.Trim()));
+ Assert.True(trimStartResult.SequenceEqual(trimStartResult.TrimStart()));
+ Assert.True(trimEndResult.SequenceEqual(trimEndResult.TrimEnd()));
+ }
+
+ // Span
+ {
+ Span<char> span = new Span<char>(a);
+ Span<char> trimResult = span.Trim();
+ Span<char> trimStartResult = span.TrimStart();
+ Span<char> trimEndResult = span.TrimEnd();
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(trimResult));
+ Assert.True(span.Slice(1).SequenceEqual(trimStartResult));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(trimEndResult));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimResult.SequenceEqual(trimResult.Trim()));
+ Assert.True(trimStartResult.SequenceEqual(trimStartResult.TrimStart()));
+ Assert.True(trimEndResult.SequenceEqual(trimEndResult.TrimEnd()));
+ }
+
+ // Memory
+ {
+ Memory<char> mem = new Memory<char>(a);
+ Memory<char> trimResult = mem.Trim();
+ Memory<char> trimStartResult = mem.TrimStart();
+ Memory<char> trimEndResult = mem.TrimEnd();
+ Assert.True(mem.Slice(1, length - 2).Span.SequenceEqual(trimResult.Span));
+ Assert.True(mem.Slice(1).Span.SequenceEqual(trimStartResult.Span));
+ Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(trimEndResult.Span));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimResult.Span.SequenceEqual(trimResult.Trim().Span));
+ Assert.True(trimStartResult.Span.SequenceEqual(trimStartResult.TrimStart().Span));
+ Assert.True(trimEndResult.Span.SequenceEqual(trimEndResult.TrimEnd().Span));
+ }
+
+ // ReadOnlyMemory
+ {
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
+ ReadOnlyMemory<char> trimResult = rom.Trim();
+ ReadOnlyMemory<char> trimStartResult = rom.TrimStart();
+ ReadOnlyMemory<char> trimEndResult = rom.TrimEnd();
+ Assert.True(rom.Slice(1, length - 2).Span.SequenceEqual(trimResult.Span));
+ Assert.True(rom.Slice(1).Span.SequenceEqual(trimStartResult.Span));
+ Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(trimEndResult.Span));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimResult.Span.SequenceEqual(trimResult.Trim().Span));
+ Assert.True(trimStartResult.Span.SequenceEqual(trimStartResult.TrimStart().Span));
+ Assert.True(trimEndResult.Span.SequenceEqual(trimEndResult.TrimEnd().Span));
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoTrimChecksGoOutOfRange_Memory()
+ {
+ for (int length = 3; length < 64; length++)
+ {
+ char[] first = new char[length];
+ first[0] = ' ';
+ first[length - 1] = ' ';
+ string s1 = new string(first, 1, length - 2);
+
+ ReadOnlySpan<char> ros = s1.AsSpan();
+ Assert.True(ros.SequenceEqual(ros.Trim()));
+ Assert.True(ros.SequenceEqual(ros.TrimStart()));
+ Assert.True(ros.SequenceEqual(ros.TrimEnd()));
+
+ Span<char> span = new Span<char>(s1.ToCharArray());
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+
+ Memory<char> mem = new Memory<char>(s1.ToCharArray());
+ Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
+ Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
+
+ ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(s1.ToCharArray());
+ Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
+ Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
+ }
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Reflection.Emit;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class StringTests
- {
- [Theory]
- [InlineData(0, 0)]
- [InlineData(3, 1)]
- public static void Ctor_CharSpan_EmptyString(int length, int offset)
- {
- Assert.Same(string.Empty, new string(new ReadOnlySpan<char>(new char[length], offset, 0)));
- }
-
- [Fact]
- public static unsafe void Ctor_CharSpan_Empty()
- {
- Assert.Same(string.Empty, new string((ReadOnlySpan<char>)null));
- Assert.Same(string.Empty, new string(ReadOnlySpan<char>.Empty));
- }
-
- [Theory]
- [InlineData(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\0' }, 0, 8, "abcdefgh")]
- [InlineData(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\0', 'i', 'j', 'k' }, 0, 12, "abcdefgh\0ijk")]
- [InlineData(new char[] { 'a', 'b', 'c' }, 0, 0, "")]
- [InlineData(new char[] { 'a', 'b', 'c' }, 0, 1, "a")]
- [InlineData(new char[] { 'a', 'b', 'c' }, 2, 1, "c")]
- [InlineData(new char[] { '\u8001', '\u8002', '\ufffd', '\u1234', '\ud800', '\udfff' }, 0, 6, "\u8001\u8002\ufffd\u1234\ud800\udfff")]
- public static void Ctor_CharSpan(char[] valueArray, int startIndex, int length, string expected)
- {
- var span = new ReadOnlySpan<char>(valueArray, startIndex, length);
- Assert.Equal(expected, new string(span));
- }
-
- [Fact]
- public static unsafe void Ctor_CharPtr_DoesNotAccessInvalidPage()
- {
- // Allocates a buffer of all 'x' followed by a null terminator,
- // then attempts to create a string instance from this at various offsets.
-
- const int MaxCharCount = 128;
- using BoundedMemory<char> boundedMemory = BoundedMemory.Allocate<char>(MaxCharCount);
- boundedMemory.Span.Fill('x');
- boundedMemory.Span[MaxCharCount - 1] = '\0';
- boundedMemory.MakeReadonly();
-
- using MemoryHandle memoryHandle = boundedMemory.Memory.Pin();
-
- for (int i = 0; i < MaxCharCount; i++)
- {
- string expectedString = new string('x', MaxCharCount - i - 1);
- string actualString = new string((char*)memoryHandle.Pointer + i);
- Assert.Equal(expectedString, actualString);
- }
- }
-
- [ConditionalFact(nameof(IsSimpleActiveCodePage))]
- public static unsafe void Ctor_SBytePtr_DoesNotAccessInvalidPage()
- {
- // Allocates a buffer of all ' ' followed by a null terminator,
- // then attempts to create a string instance from this at various offsets.
- // We use U+0020 SPACE instead of any other character because it lives
- // at offset 0x20 across every supported code page.
-
- const int MaxByteCount = 128;
- using BoundedMemory<sbyte> boundedMemory = BoundedMemory.Allocate<sbyte>(MaxByteCount);
- boundedMemory.Span.Fill((sbyte)' ');
- boundedMemory.Span[MaxByteCount - 1] = (sbyte)'\0';
- boundedMemory.MakeReadonly();
-
- using MemoryHandle memoryHandle = boundedMemory.Memory.Pin();
-
- for (int i = 0; i < MaxByteCount; i++)
- {
- string expectedString = new string(' ', MaxByteCount - i - 1);
- string actualString = new string((sbyte*)memoryHandle.Pointer + i);
- Assert.Equal(expectedString, actualString);
- }
- }
-
- [Fact]
- public static void Create_InvalidArguments_Throw()
- {
- AssertExtensions.Throws<ArgumentNullException>("action", () => string.Create(-1, 0, null));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => string.Create(-1, 0, (span, state) => { }));
- }
-
- [Fact]
- public static void Create_Length0_ReturnsEmptyString()
- {
- bool actionInvoked = false;
- Assert.Same(string.Empty, string.Create(0, 0, (span, state) => actionInvoked = true));
- Assert.False(actionInvoked);
- }
-
- [Fact]
- public static void Create_NullState_Allowed()
- {
- string result = string.Create(1, (object)null, (span, state) =>
- {
- span[0] = 'a';
- Assert.Null(state);
- });
- Assert.Equal("a", result);
- }
-
- [Fact]
- public static void Create_ClearsMemory()
- {
- const int Length = 10;
- string result = string.Create(Length, (object)null, (span, state) =>
- {
- for (int i = 0; i < span.Length; i++)
- {
- Assert.Equal('\0', span[i]);
- }
- });
- Assert.Equal(new string('\0', Length), result);
- }
-
- [Theory]
- [InlineData("a")]
- [InlineData("this is a test")]
- [InlineData("\0\u8001\u8002\ufffd\u1234\ud800\udfff")]
- public static void Create_ReturnsExpectedString(string expected)
- {
- char[] input = expected.ToCharArray();
- string result = string.Create(input.Length, input, (span, state) =>
- {
- Assert.Same(input, state);
- for (int i = 0; i < state.Length; i++)
- {
- span[i] = state[i];
- }
- });
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [InlineData("Hello", 'H', true)]
- [InlineData("Hello", 'Z', false)]
- [InlineData("Hello", 'e', true)]
- [InlineData("Hello", 'E', false)]
- [InlineData("", 'H', false)]
- public static void Contains(string s, char value, bool expected)
- {
- Assert.Equal(expected, s.Contains(value));
-
- ReadOnlySpan<char> span = s.AsSpan();
- Assert.Equal(expected, span.Contains(value));
- }
-
- [Theory]
- // CurrentCulture
- [InlineData("Hello", 'H', StringComparison.CurrentCulture, true)]
- [InlineData("Hello", 'Z', StringComparison.CurrentCulture, false)]
- [InlineData("Hello", 'e', StringComparison.CurrentCulture, true)]
- [InlineData("Hello", 'E', StringComparison.CurrentCulture, false)]
- [InlineData("", 'H', StringComparison.CurrentCulture, false)]
- // CurrentCultureIgnoreCase
- [InlineData("Hello", 'H', StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("Hello", 'Z', StringComparison.CurrentCultureIgnoreCase, false)]
- [InlineData("Hello", 'e', StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("Hello", 'E', StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("", 'H', StringComparison.CurrentCultureIgnoreCase, false)]
- // InvariantCulture
- [InlineData("Hello", 'H', StringComparison.InvariantCulture, true)]
- [InlineData("Hello", 'Z', StringComparison.InvariantCulture, false)]
- [InlineData("Hello", 'e', StringComparison.InvariantCulture, true)]
- [InlineData("Hello", 'E', StringComparison.InvariantCulture, false)]
- [InlineData("", 'H', StringComparison.InvariantCulture, false)]
- // InvariantCultureIgnoreCase
- [InlineData("Hello", 'H', StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("Hello", 'Z', StringComparison.InvariantCultureIgnoreCase, false)]
- [InlineData("Hello", 'e', StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("Hello", 'E', StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("", 'H', StringComparison.InvariantCultureIgnoreCase, false)]
- // Ordinal
- [InlineData("Hello", 'H', StringComparison.Ordinal, true)]
- [InlineData("Hello", 'Z', StringComparison.Ordinal, false)]
- [InlineData("Hello", 'e', StringComparison.Ordinal, true)]
- [InlineData("Hello", 'E', StringComparison.Ordinal, false)]
- [InlineData("", 'H', StringComparison.Ordinal, false)]
- // OrdinalIgnoreCase
- [InlineData("Hello", 'H', StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("Hello", 'Z', StringComparison.OrdinalIgnoreCase, false)]
- [InlineData("Hello", 'e', StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("Hello", 'E', StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("", 'H', StringComparison.OrdinalIgnoreCase, false)]
- public static void Contains(string s, char value, StringComparison comparisionType, bool expected)
- {
- Assert.Equal(expected, s.Contains(value, comparisionType));
- }
-
- [Theory]
- // CurrentCulture
- [InlineData("Hello", "ello", StringComparison.CurrentCulture, true)]
- [InlineData("Hello", "ELL", StringComparison.CurrentCulture, false)]
- [InlineData("Hello", "ElLo", StringComparison.CurrentCulture, false)]
- [InlineData("Hello", "Larger Hello", StringComparison.CurrentCulture, false)]
- [InlineData("Hello", "Goodbye", StringComparison.CurrentCulture, false)]
- [InlineData("", "", StringComparison.CurrentCulture, true)]
- [InlineData("", "hello", StringComparison.CurrentCulture, false)]
- [InlineData("Hello", "", StringComparison.CurrentCulture, true)]
- [InlineData("Hello", "ell" + SoftHyphen, StringComparison.CurrentCulture, true)]
- [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.CurrentCulture, false)]
- // CurrentCultureIgnoreCase
- [InlineData("Hello", "ello", StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("Hello", "ELL", StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("Hello", "ElLo", StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("Hello", "Larger Hello", StringComparison.CurrentCultureIgnoreCase, false)]
- [InlineData("Hello", "Goodbye", StringComparison.CurrentCultureIgnoreCase, false)]
- [InlineData("", "", StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("", "hello", StringComparison.CurrentCultureIgnoreCase, false)]
- [InlineData("Hello", "", StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("Hello", "ell" + SoftHyphen, StringComparison.CurrentCultureIgnoreCase, true)]
- [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.CurrentCultureIgnoreCase, true)]
- // InvariantCulture
- [InlineData("Hello", "ello", StringComparison.InvariantCulture, true)]
- [InlineData("Hello", "ELL", StringComparison.InvariantCulture, false)]
- [InlineData("Hello", "ElLo", StringComparison.InvariantCulture, false)]
- [InlineData("Hello", "Larger Hello", StringComparison.InvariantCulture, false)]
- [InlineData("Hello", "Goodbye", StringComparison.InvariantCulture, false)]
- [InlineData("", "", StringComparison.InvariantCulture, true)]
- [InlineData("", "hello", StringComparison.InvariantCulture, false)]
- [InlineData("Hello", "", StringComparison.InvariantCulture, true)]
- [InlineData("Hello", "ell" + SoftHyphen, StringComparison.InvariantCulture, true)]
- [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.InvariantCulture, false)]
- // InvariantCultureIgnoreCase
- [InlineData("Hello", "ello", StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("Hello", "ELL", StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("Hello", "ElLo", StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("Hello", "Larger Hello", StringComparison.InvariantCultureIgnoreCase, false)]
- [InlineData("Hello", "Goodbye", StringComparison.InvariantCultureIgnoreCase, false)]
- [InlineData("", "", StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("", "hello", StringComparison.InvariantCultureIgnoreCase, false)]
- [InlineData("Hello", "", StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("Hello", "ell" + SoftHyphen, StringComparison.InvariantCultureIgnoreCase, true)]
- [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.InvariantCultureIgnoreCase, true)]
- // Ordinal
- [InlineData("Hello", "ello", StringComparison.Ordinal, true)]
- [InlineData("Hello", "ELL", StringComparison.Ordinal, false)]
- [InlineData("Hello", "ElLo", StringComparison.Ordinal, false)]
- [InlineData("Hello", "Larger Hello", StringComparison.Ordinal, false)]
- [InlineData("Hello", "Goodbye", StringComparison.Ordinal, false)]
- [InlineData("", "", StringComparison.Ordinal, true)]
- [InlineData("", "hello", StringComparison.Ordinal, false)]
- [InlineData("Hello", "", StringComparison.Ordinal, true)]
- [InlineData("Hello", "ell" + SoftHyphen, StringComparison.Ordinal, false)]
- [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.Ordinal, false)]
- // OrdinalIgnoreCase
- [InlineData("Hello", "ello", StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("Hello", "ELL", StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("Hello", "ElLo", StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("Hello", "Larger Hello", StringComparison.OrdinalIgnoreCase, false)]
- [InlineData("Hello", "Goodbye", StringComparison.OrdinalIgnoreCase, false)]
- [InlineData("", "", StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("", "hello", StringComparison.OrdinalIgnoreCase, false)]
- [InlineData("Hello", "", StringComparison.OrdinalIgnoreCase, true)]
- [InlineData("Hello", "ell" + SoftHyphen, StringComparison.OrdinalIgnoreCase, false)]
- [InlineData("Hello", "Ell" + SoftHyphen, StringComparison.OrdinalIgnoreCase, false)]
- public static void Contains(string s, string value, StringComparison comparisonType, bool expected)
- {
- Assert.Equal(expected, s.Contains(value, comparisonType));
- Assert.Equal(expected, s.AsSpan().Contains(value, comparisonType));
- }
-
- [Fact]
- public static void Contains_StringComparison_TurkishI()
- {
- const string Source = "\u0069\u0130";
-
- using (new ThreadCultureChange("tr-TR"))
- {
- Assert.True(Source.Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
- Assert.True(Source.AsSpan().Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
- }
-
- using (new ThreadCultureChange("en-US"))
- {
- Assert.False(Source.Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
- Assert.False(Source.AsSpan().Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
- }
- }
-
- [Fact]
- public static void Contains_Match_Char()
- {
- Assert.False("".Contains('a'));
- Assert.False("".AsSpan().Contains('a'));
-
- // Use a long-enough string to incur vectorization code
- const int max = 250;
-
- for (var length = 1; length < max; length++)
- {
- char[] ca = new char[length];
- for (int i = 0; i < length; i++)
- {
- ca[i] = (char)(i + 1);
- }
-
- var span = new Span<char>(ca);
- var ros = new ReadOnlySpan<char>(ca);
- var str = new string(ca);
-
- for (var targetIndex = 0; targetIndex < length; targetIndex++)
- {
- char target = ca[targetIndex];
-
- // Span
- bool found = span.Contains(target);
- Assert.True(found);
-
- // ReadOnlySpan
- found = ros.Contains(target);
- Assert.True(found);
-
- // String
- found = str.Contains(target);
- Assert.True(found);
- }
- }
- }
-
- [Fact]
- public static void Contains_ZeroLength_Char()
- {
- // Span
- var span = new Span<char>(Array.Empty<char>());
- bool found = span.Contains((char)0);
- Assert.False(found);
-
- span = Span<char>.Empty;
- found = span.Contains((char)0);
- Assert.False(found);
-
- // ReadOnlySpan
- var ros = new ReadOnlySpan<char>(Array.Empty<char>());
- found = ros.Contains((char)0);
- Assert.False(found);
-
- ros = ReadOnlySpan<char>.Empty;
- found = ros.Contains((char)0);
- Assert.False(found);
-
- // String
- found = string.Empty.Contains((char)0);
- Assert.False(found);
- }
-
- [Fact]
- public static void Contains_MultipleMatches_Char()
- {
- for (int length = 2; length < 32; length++)
- {
- var ca = new char[length];
- for (int i = 0; i < length; i++)
- {
- ca[i] = (char)(i + 1);
- }
-
- ca[length - 1] = (char)200;
- ca[length - 2] = (char)200;
-
- // Span
- var span = new Span<char>(ca);
- bool found = span.Contains((char)200);
- Assert.True(found);
-
- // ReadOnlySpan
- var ros = new ReadOnlySpan<char>(ca);
- found = ros.Contains((char)200);
- Assert.True(found);
-
- // String
- var str = new string(ca);
- found = str.Contains((char)200);
- Assert.True(found);
- }
- }
-
- [Fact]
- public static void Contains_EnsureNoChecksGoOutOfRange_Char()
- {
- for (int length = 0; length < 100; length++)
- {
- var ca = new char[length + 2];
- ca[0] = '9';
- ca[length + 1] = '9';
-
- // Span
- var span = new Span<char>(ca, 1, length);
- bool found = span.Contains('9');
- Assert.False(found);
-
- // ReadOnlySpan
- var ros = new ReadOnlySpan<char>(ca, 1, length);
- found = ros.Contains('9');
- Assert.False(found);
-
- // String
- var str = new string(ca, 1, length);
- found = str.Contains('9');
- Assert.False(found);
- }
- }
-
- [Theory]
- [InlineData(StringComparison.CurrentCulture)]
- [InlineData(StringComparison.CurrentCultureIgnoreCase)]
- [InlineData(StringComparison.InvariantCulture)]
- [InlineData(StringComparison.InvariantCultureIgnoreCase)]
- [InlineData(StringComparison.Ordinal)]
- [InlineData(StringComparison.OrdinalIgnoreCase)]
- public static void Contains_NullValue_ThrowsArgumentNullException(StringComparison comparisonType)
- {
- AssertExtensions.Throws<ArgumentNullException>("value", () => "foo".Contains(null, comparisonType));
- }
-
- [Theory]
- [InlineData(StringComparison.CurrentCulture - 1)]
- [InlineData(StringComparison.OrdinalIgnoreCase + 1)]
- public static void Contains_InvalidComparisonType_ThrowsArgumentOutOfRangeException(StringComparison comparisonType)
- {
- AssertExtensions.Throws<ArgumentException>("comparisonType", () => "ab".Contains("a", comparisonType));
- }
-
- [Theory]
- [InlineData("Hello", 'o', true)]
- [InlineData("Hello", 'O', false)]
- [InlineData("o", 'o', true)]
- [InlineData("o", 'O', false)]
- [InlineData("Hello", 'e', false)]
- [InlineData("Hello", '\0', false)]
- [InlineData("", '\0', false)]
- [InlineData("\0", '\0', true)]
- [InlineData("", 'a', false)]
- [InlineData("abcdefghijklmnopqrstuvwxyz", 'z', true)]
- public static void EndsWith(string s, char value, bool expected)
- {
- Assert.Equal(expected, s.EndsWith(value));
- }
-
- [Theory]
- [InlineData(new char[0], new int[0])] // empty
- [InlineData(new char[] { 'x', 'y', 'z' }, new int[] { 'x', 'y', 'z' })]
- [InlineData(new char[] { 'x', '\uD86D', '\uDF54', 'y' }, new int[] { 'x', 0x2B754, 'y' })] // valid surrogate pair
- [InlineData(new char[] { 'x', '\uD86D', 'y' }, new int[] { 'x', 0xFFFD, 'y' })] // standalone high surrogate
- [InlineData(new char[] { 'x', '\uDF54', 'y' }, new int[] { 'x', 0xFFFD, 'y' })] // standalone low surrogate
- [InlineData(new char[] { 'x', '\uD86D' }, new int[] { 'x', 0xFFFD })] // standalone high surrogate at end of string
- [InlineData(new char[] { 'x', '\uDF54' }, new int[] { 'x', 0xFFFD })] // standalone low surrogate at end of string
- [InlineData(new char[] { 'x', '\uD86D', '\uD86D', 'y' }, new int[] { 'x', 0xFFFD, 0xFFFD, 'y' })] // two high surrogates should be two replacement chars
- [InlineData(new char[] { 'x', '\uFFFD', 'y' }, new int[] { 'x', 0xFFFD, 'y' })] // literal U+FFFD
- public static void EnumerateRunes(char[] chars, int[] expected)
- {
- // Test data is smuggled as char[] instead of straight-up string since the test framework
- // doesn't like invalid UTF-16 literals.
-
- string asString = new string(chars);
-
- // First, use a straight-up foreach keyword to ensure pattern matching works as expected
-
- List<int> enumeratedScalarValues = new List<int>();
- foreach (Rune rune in asString.EnumerateRunes())
- {
- enumeratedScalarValues.Add(rune.Value);
- }
- Assert.Equal(expected, enumeratedScalarValues.ToArray());
-
- // Then use LINQ to ensure IEnumerator<...> works as expected
-
- int[] enumeratedValues = new string(chars).EnumerateRunes().Select(r => r.Value).ToArray();
- Assert.Equal(expected, enumeratedValues);
- }
-
- [Theory]
- [InlineData("Hello", 'H', true)]
- [InlineData("Hello", 'h', false)]
- [InlineData("H", 'H', true)]
- [InlineData("H", 'h', false)]
- [InlineData("Hello", 'e', false)]
- [InlineData("Hello", '\0', false)]
- [InlineData("", '\0', false)]
- [InlineData("\0", '\0', true)]
- [InlineData("", 'a', false)]
- [InlineData("abcdefghijklmnopqrstuvwxyz", 'a', true)]
- public static void StartsWith(string s, char value, bool expected)
- {
- Assert.Equal(expected, s.StartsWith(value));
- }
-
- public static IEnumerable<object[]> Join_Char_StringArray_TestData()
- {
- yield return new object[] { '|', new string[0], 0, 0, "" };
- yield return new object[] { '|', new string[] { "a" }, 0, 1, "a" };
- yield return new object[] { '|', new string[] { "a", "b", "c" }, 0, 3, "a|b|c" };
- yield return new object[] { '|', new string[] { "a", "b", "c" }, 0, 2, "a|b" };
- yield return new object[] { '|', new string[] { "a", "b", "c" }, 1, 1, "b" };
- yield return new object[] { '|', new string[] { "a", "b", "c" }, 1, 2, "b|c" };
- yield return new object[] { '|', new string[] { "a", "b", "c" }, 3, 0, "" };
- yield return new object[] { '|', new string[] { "a", "b", "c" }, 0, 0, "" };
- yield return new object[] { '|', new string[] { "", "", "" }, 0, 3, "||" };
- yield return new object[] { '|', new string[] { null, null, null }, 0, 3, "||" };
- }
-
- [Theory]
- [MemberData(nameof(Join_Char_StringArray_TestData))]
- public static void Join_Char_StringArray(char separator, string[] values, int startIndex, int count, string expected)
- {
- if (startIndex == 0 && count == values.Length)
- {
- Assert.Equal(expected, string.Join(separator, values));
- Assert.Equal(expected, string.Join(separator, (IEnumerable<string>)values));
- Assert.Equal(expected, string.Join(separator, (object[])values));
- Assert.Equal(expected, string.Join(separator, (IEnumerable<object>)values));
- }
-
- Assert.Equal(expected, string.Join(separator, values, startIndex, count));
- Assert.Equal(expected, string.Join(separator.ToString(), values, startIndex, count));
- }
-
- public static IEnumerable<object[]> Join_Char_ObjectArray_TestData()
- {
- yield return new object[] { '|', new object[0], "" };
- yield return new object[] { '|', new object[] { 1 }, "1" };
- yield return new object[] { '|', new object[] { 1, 2, 3 }, "1|2|3" };
- yield return new object[] { '|', new object[] { new ObjectWithNullToString(), 2, new ObjectWithNullToString() }, "|2|" };
- yield return new object[] { '|', new object[] { "1", null, "3" }, "1||3" };
- yield return new object[] { '|', new object[] { "", "", "" }, "||" };
- yield return new object[] { '|', new object[] { "", null, "" }, "||" };
- yield return new object[] { '|', new object[] { null, null, null }, "||" };
- }
-
- [Theory]
- [MemberData(nameof(Join_Char_ObjectArray_TestData))]
- public static void Join_Char_ObjectArray(char separator, object[] values, string expected)
- {
- Assert.Equal(expected, string.Join(separator, values));
- Assert.Equal(expected, string.Join(separator, (IEnumerable<object>)values));
- }
-
- [Fact]
- public static void Join_Char_NullValues_ThrowsArgumentNullException()
- {
- AssertExtensions.Throws<ArgumentNullException>("value", () => string.Join('|', (string[])null));
- AssertExtensions.Throws<ArgumentNullException>("value", () => string.Join('|', (string[])null, 0, 0));
- AssertExtensions.Throws<ArgumentNullException>("values", () => string.Join('|', (object[])null));
- AssertExtensions.Throws<ArgumentNullException>("values", () => string.Join('|', (IEnumerable<object>)null));
- }
-
- [Fact]
- public static void Join_Char_NegativeStartIndex_ThrowsArgumentOutOfRangeException()
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("startIndex", () => string.Join('|', new string[] { "Foo" }, -1, 0));
- }
-
- [Fact]
- public static void Join_Char_NegativeCount_ThrowsArgumentOutOfRangeException()
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => string.Join('|', new string[] { "Foo" }, 0, -1));
- }
-
- [Theory]
- [InlineData(2, 1)]
- [InlineData(2, 0)]
- [InlineData(1, 2)]
- [InlineData(1, 1)]
- [InlineData(0, 2)]
- [InlineData(-1, 0)]
- public static void Join_Char_InvalidStartIndexCount_ThrowsArgumentOutOfRangeException(int startIndex, int count)
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("startIndex", () => string.Join('|', new string[] { "Foo" }, startIndex, count));
- }
-
- public static IEnumerable<object[]> Replace_StringComparison_TestData()
- {
- yield return new object[] { "abc", "abc", "def", StringComparison.CurrentCulture, "def" };
- yield return new object[] { "abc", "ABC", "def", StringComparison.CurrentCulture, "abc" };
- yield return new object[] { "abc", "abc", "", StringComparison.CurrentCulture, "" };
- yield return new object[] { "abc", "b", "LONG", StringComparison.CurrentCulture, "aLONGc" };
- yield return new object[] { "abc", "b", "d", StringComparison.CurrentCulture, "adc" };
- yield return new object[] { "abc", "b", null, StringComparison.CurrentCulture, "ac" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.CurrentCulture, "def" };
-
- yield return new object[] { "abc", "abc", "def", StringComparison.CurrentCultureIgnoreCase, "def" };
- yield return new object[] { "abc", "ABC", "def", StringComparison.CurrentCultureIgnoreCase, "def" };
- yield return new object[] { "abc", "abc", "", StringComparison.CurrentCultureIgnoreCase, "" };
- yield return new object[] { "abc", "b", "LONG", StringComparison.CurrentCultureIgnoreCase, "aLONGc" };
- yield return new object[] { "abc", "b", "d", StringComparison.CurrentCultureIgnoreCase, "adc" };
- yield return new object[] { "abc", "b", null, StringComparison.CurrentCultureIgnoreCase, "ac" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.CurrentCultureIgnoreCase, "def" };
-
- yield return new object[] { "abc", "abc", "def", StringComparison.Ordinal, "def" };
- yield return new object[] { "abc", "ABC", "def", StringComparison.Ordinal, "abc" };
- yield return new object[] { "abc", "abc", "", StringComparison.Ordinal, "" };
- yield return new object[] { "abc", "b", "LONG", StringComparison.Ordinal, "aLONGc" };
- yield return new object[] { "abc", "b", "d", StringComparison.Ordinal, "adc" };
- yield return new object[] { "abc", "b", null, StringComparison.Ordinal, "ac" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.Ordinal, "abc" };
-
- yield return new object[] { "abc", "abc", "def", StringComparison.OrdinalIgnoreCase, "def" };
- yield return new object[] { "abc", "ABC", "def", StringComparison.OrdinalIgnoreCase, "def" };
- yield return new object[] { "abc", "abc", "", StringComparison.OrdinalIgnoreCase, "" };
- yield return new object[] { "abc", "b", "LONG", StringComparison.OrdinalIgnoreCase, "aLONGc" };
- yield return new object[] { "abc", "b", "d", StringComparison.OrdinalIgnoreCase, "adc" };
- yield return new object[] { "abc", "b", null, StringComparison.OrdinalIgnoreCase, "ac" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.OrdinalIgnoreCase, "abc" };
-
- yield return new object[] { "abc", "abc", "def", StringComparison.InvariantCulture, "def" };
- yield return new object[] { "abc", "ABC", "def", StringComparison.InvariantCulture, "abc" };
- yield return new object[] { "abc", "abc", "", StringComparison.InvariantCulture, "" };
- yield return new object[] { "abc", "b", "LONG", StringComparison.InvariantCulture, "aLONGc" };
- yield return new object[] { "abc", "b", "d", StringComparison.InvariantCulture, "adc" };
- yield return new object[] { "abc", "b", null, StringComparison.InvariantCulture, "ac" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.InvariantCulture, "def" };
-
- yield return new object[] { "abc", "abc", "def", StringComparison.InvariantCultureIgnoreCase, "def" };
- yield return new object[] { "abc", "ABC", "def", StringComparison.InvariantCultureIgnoreCase, "def" };
- yield return new object[] { "abc", "abc", "", StringComparison.InvariantCultureIgnoreCase, "" };
- yield return new object[] { "abc", "b", "LONG", StringComparison.InvariantCultureIgnoreCase, "aLONGc" };
- yield return new object[] { "abc", "b", "d", StringComparison.InvariantCultureIgnoreCase, "adc" };
- yield return new object[] { "abc", "b", null, StringComparison.InvariantCultureIgnoreCase, "ac" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", StringComparison.InvariantCultureIgnoreCase, "def" };
-
- string turkishSource = "\u0069\u0130";
-
- yield return new object[] { turkishSource, "\u0069", "a", StringComparison.Ordinal, "a\u0130" };
- yield return new object[] { turkishSource, "\u0069", "a", StringComparison.OrdinalIgnoreCase, "a\u0130" };
- yield return new object[] { turkishSource, "\u0130", "a", StringComparison.Ordinal, "\u0069a" };
- yield return new object[] { turkishSource, "\u0130", "a", StringComparison.OrdinalIgnoreCase, "\u0069a" };
-
- yield return new object[] { turkishSource, "\u0069", "a", StringComparison.InvariantCulture, "a\u0130" };
- yield return new object[] { turkishSource, "\u0069", "a", StringComparison.InvariantCultureIgnoreCase, "a\u0130" };
- yield return new object[] { turkishSource, "\u0130", "a", StringComparison.InvariantCulture, "\u0069a" };
- yield return new object[] { turkishSource, "\u0130", "a", StringComparison.InvariantCultureIgnoreCase, "\u0069a" };
- }
-
- [Theory]
- [MemberData(nameof(Replace_StringComparison_TestData))]
- public void Replace_StringComparison_ReturnsExpected(string original, string oldValue, string newValue, StringComparison comparisonType, string expected)
- {
- Assert.Equal(expected, original.Replace(oldValue, newValue, comparisonType));
- }
-
- [Fact]
- public void Replace_StringComparison_TurkishI()
- {
- const string Source = "\u0069\u0130";
-
- using (new ThreadCultureChange("tr-TR"))
- {
- Assert.True("\u0069".Equals("\u0130", StringComparison.CurrentCultureIgnoreCase));
-
- Assert.Equal("a\u0130", Source.Replace("\u0069", "a", StringComparison.CurrentCulture));
- Assert.Equal("aa", Source.Replace("\u0069", "a", StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal("\u0069a", Source.Replace("\u0130", "a", StringComparison.CurrentCulture));
- Assert.Equal("aa", Source.Replace("\u0130", "a", StringComparison.CurrentCultureIgnoreCase));
- }
-
- using (new ThreadCultureChange("en-US"))
- {
- Assert.False("\u0069".Equals("\u0130", StringComparison.CurrentCultureIgnoreCase));
-
- Assert.Equal("a\u0130", Source.Replace("\u0069", "a", StringComparison.CurrentCulture));
- Assert.Equal("a\u0130", Source.Replace("\u0069", "a", StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal("\u0069a", Source.Replace("\u0130", "a", StringComparison.CurrentCulture));
- Assert.Equal("\u0069a", Source.Replace("\u0130", "a", StringComparison.CurrentCultureIgnoreCase));
- }
- }
-
- public static IEnumerable<object[]> Replace_StringComparisonCulture_TestData()
- {
- yield return new object[] { "abc", "abc", "def", false, null, "def" };
- yield return new object[] { "abc", "ABC", "def", false, null, "abc" };
- yield return new object[] { "abc", "abc", "def", false, CultureInfo.InvariantCulture, "def" };
- yield return new object[] { "abc", "ABC", "def", false, CultureInfo.InvariantCulture, "abc" };
-
- yield return new object[] { "abc", "abc", "def", true, null, "def" };
- yield return new object[] { "abc", "ABC", "def", true, null, "def" };
- yield return new object[] { "abc", "abc", "def", true, CultureInfo.InvariantCulture, "def" };
- yield return new object[] { "abc", "ABC", "def", true, CultureInfo.InvariantCulture, "def" };
-
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", false, null, "def" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", true, null, "def" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", false, CultureInfo.InvariantCulture, "def" };
- yield return new object[] { "abc", "abc" + SoftHyphen, "def", true, CultureInfo.InvariantCulture, "def" };
-
- yield return new object[] { "\u0069\u0130", "\u0069", "a", false, new CultureInfo("tr-TR"), "a\u0130" };
- yield return new object[] { "\u0069\u0130", "\u0069", "a", true, new CultureInfo("tr-TR"), "aa" };
- yield return new object[] { "\u0069\u0130", "\u0069", "a", false, CultureInfo.InvariantCulture, "a\u0130" };
- yield return new object[] { "\u0069\u0130", "\u0069", "a", true, CultureInfo.InvariantCulture, "a\u0130" };
- }
-
- [Theory]
- [MemberData(nameof(Replace_StringComparisonCulture_TestData))]
- public void Replace_StringComparisonCulture_ReturnsExpected(string original, string oldValue, string newValue, bool ignoreCase, CultureInfo culture, string expected)
- {
- Assert.Equal(expected, original.Replace(oldValue, newValue, ignoreCase, culture));
- if (culture == null)
- {
- Assert.Equal(expected, original.Replace(oldValue, newValue, ignoreCase, CultureInfo.CurrentCulture));
- }
- }
-
- [Fact]
- public void Replace_StringComparison_NullOldValue_ThrowsArgumentException()
- {
- AssertExtensions.Throws<ArgumentNullException>("oldValue", () => "abc".Replace(null, "def", StringComparison.CurrentCulture));
- AssertExtensions.Throws<ArgumentNullException>("oldValue", () => "abc".Replace(null, "def", true, CultureInfo.CurrentCulture));
- }
-
- [Fact]
- public void Replace_StringComparison_EmptyOldValue_ThrowsArgumentException()
- {
- AssertExtensions.Throws<ArgumentException>("oldValue", () => "abc".Replace("", "def", StringComparison.CurrentCulture));
- AssertExtensions.Throws<ArgumentException>("oldValue", () => "abc".Replace("", "def", true, CultureInfo.CurrentCulture));
- }
-
- [Theory]
- [InlineData(StringComparison.CurrentCulture - 1)]
- [InlineData(StringComparison.OrdinalIgnoreCase + 1)]
- public void Replace_NoSuchStringComparison_ThrowsArgumentException(StringComparison comparisonType)
- {
- AssertExtensions.Throws<ArgumentException>("comparisonType", () => "abc".Replace("abc", "def", comparisonType));
- }
-
-
- private static readonly StringComparison[] StringComparisons = (StringComparison[])Enum.GetValues(typeof(StringComparison));
-
- [Fact]
- public static void GetHashCode_OfSpan_EmbeddedNull_ReturnsDifferentHashCodes()
- {
- Assert.NotEqual(string.GetHashCode("\0AAAAAAAAA".AsSpan()), string.GetHashCode("\0BBBBBBBBBBBB".AsSpan()));
- }
-
- [Fact]
- public static void GetHashCode_OfSpan_MatchesOfString()
- {
- // parameterless should be ordinal only
- Assert.Equal("abc".GetHashCode(), string.GetHashCode("abc".AsSpan()));
- Assert.NotEqual("abc".GetHashCode(), string.GetHashCode("ABC".AsSpan())); // case differences
- }
-
- [Fact]
- public static void GetHashCode_CompareInfo()
- {
- // ordinal
- Assert.Equal("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc", CompareOptions.Ordinal));
- Assert.NotEqual("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC", CompareOptions.Ordinal));
-
- // ordinal ignore case
- Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc", CompareOptions.OrdinalIgnoreCase));
- Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC", CompareOptions.OrdinalIgnoreCase));
-
- // culture-aware
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCulture), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.None));
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCultureIgnoreCase), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.IgnoreCase));
-
- // invariant culture
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCulture), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.None));
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCultureIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc", CompareOptions.IgnoreCase));
- }
-
- [Fact]
- public static void GetHashCode_CompareInfo_OfSpan()
- {
- // ordinal
- Assert.Equal("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc".AsSpan(), CompareOptions.Ordinal));
- Assert.NotEqual("abc".GetHashCode(), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC".AsSpan(), CompareOptions.Ordinal));
-
- // ordinal ignore case
- Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("abc".AsSpan(), CompareOptions.OrdinalIgnoreCase));
- Assert.Equal("abc".GetHashCode(StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("ABC".AsSpan(), CompareOptions.OrdinalIgnoreCase));
-
- // culture-aware
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCulture), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.None));
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.CurrentCultureIgnoreCase), CultureInfo.CurrentCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.IgnoreCase));
-
- // invariant culture
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCulture), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.None));
- Assert.Equal("aeiXXabc".GetHashCode(StringComparison.InvariantCultureIgnoreCase), CultureInfo.InvariantCulture.CompareInfo.GetHashCode("aeiXXabc".AsSpan(), CompareOptions.IgnoreCase));
- }
-
- public static IEnumerable<object[]> GetHashCode_StringComparison_Data => StringComparisons.Select(value => new object[] { value });
-
- [Theory]
- [MemberData(nameof(GetHashCode_StringComparison_Data))]
- public static void GetHashCode_StringComparison(StringComparison comparisonType)
- {
- int hashCodeFromStringComparer = StringComparer.FromComparison(comparisonType).GetHashCode("abc");
- int hashCodeFromStringGetHashCode = "abc".GetHashCode(comparisonType);
- int hashCodeFromStringGetHashCodeOfSpan = string.GetHashCode("abc".AsSpan(), comparisonType);
-
- Assert.Equal(hashCodeFromStringComparer, hashCodeFromStringGetHashCode);
- Assert.Equal(hashCodeFromStringComparer, hashCodeFromStringGetHashCodeOfSpan);
- }
-
- public static IEnumerable<object[]> GetHashCode_NoSuchStringComparison_ThrowsArgumentException_Data => new[]
- {
- new object[] { StringComparisons.Min() - 1 },
- new object[] { StringComparisons.Max() + 1 },
- };
-
- [Theory]
- [MemberData(nameof(GetHashCode_NoSuchStringComparison_ThrowsArgumentException_Data))]
- public static void GetHashCode_NoSuchStringComparison_ThrowsArgumentException(StringComparison comparisonType)
- {
- AssertExtensions.Throws<ArgumentException>("comparisonType", () => "abc".GetHashCode(comparisonType));
- AssertExtensions.Throws<ArgumentException>("comparisonType", () => string.GetHashCode("abc".AsSpan(), comparisonType));
- }
-
- [Theory]
- [InlineData("")] // empty string
- [InlineData("hello")] // non-empty string
- public static unsafe void GetPinnableReference_ReturnsSameAsGCHandleAndLegacyFixed(string input)
- {
- Assert.NotNull(input); // test shouldn't have null input
-
- // First, ensure the value pointed to by GetPinnableReference is correct.
- // It should point to the first character (or the null terminator for empty inputs).
-
- ref readonly char rChar = ref input.GetPinnableReference();
- Assert.Equal((input.Length > 0) ? input[0] : '\0', rChar);
-
- // Next, ensure that GetPinnableReference() and GCHandle.AddrOfPinnedObject agree
- // on the address being returned.
-
- GCHandle gcHandle = GCHandle.Alloc(input, GCHandleType.Pinned);
- try
- {
- Assert.Equal((IntPtr)Unsafe.AsPointer(ref Unsafe.AsRef(in rChar)), gcHandle.AddrOfPinnedObject());
- }
- finally
- {
- gcHandle.Free();
- }
-
- // Next, ensure that GetPinnableReference matches the string projected as a ROS<char>.
-
- Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in rChar), ref MemoryMarshal.GetReference((ReadOnlySpan<char>)input)));
-
- // Finally, ensure that GetPinnableReference matches the legacy 'fixed' keyword.
-
- DynamicMethod dynamicMethod = new DynamicMethod("tester", typeof(bool), new[] { typeof(string) });
- ILGenerator ilGen = dynamicMethod.GetILGenerator();
- LocalBuilder pinnedLocal = ilGen.DeclareLocal(typeof(object), pinned: true);
-
- ilGen.Emit(OpCodes.Ldarg_0); // load 'input' and pin it
- ilGen.Emit(OpCodes.Stloc, pinnedLocal);
-
- ilGen.Emit(OpCodes.Ldloc, pinnedLocal); // get the address of field 0 from pinned 'input'
- ilGen.Emit(OpCodes.Conv_I);
-
- ilGen.Emit(OpCodes.Call, typeof(RuntimeHelpers).GetProperty("OffsetToStringData").GetMethod); // get pointer to start of string data
- ilGen.Emit(OpCodes.Add);
-
- ilGen.Emit(OpCodes.Ldarg_0); // get value of input.GetPinnableReference()
- ilGen.Emit(OpCodes.Callvirt, typeof(string).GetMethod("GetPinnableReference"));
-
- // At this point, the top of the evaluation stack is traditional (fixed char* = input) and input.GetPinnableReference().
- // Compare for equality and return.
-
- ilGen.Emit(OpCodes.Ceq);
- ilGen.Emit(OpCodes.Ret);
-
- Assert.True((bool)dynamicMethod.Invoke(null, new[] { input }));
- }
-
- [Fact]
- public static unsafe void GetPinnableReference_WithNullInput_ThrowsNullRef()
- {
- // This test uses an explicit call instead of the normal callvirt that C# would emit.
- // This allows us to make sure the NullReferenceException is coming from *within*
- // the GetPinnableReference method rather than on the call site to that method.
-
- DynamicMethod dynamicMethod = new DynamicMethod("tester", typeof(void), Type.EmptyTypes);
- ILGenerator ilGen = dynamicMethod.GetILGenerator();
-
- ilGen.Emit(OpCodes.Ldnull);
- ilGen.Emit(OpCodes.Call, typeof(string).GetMethod("GetPinnableReference"));
- ilGen.Emit(OpCodes.Pop);
- ilGen.Emit(OpCodes.Ret);
-
- Action del = (Action)dynamicMethod.CreateDelegate(typeof(Action));
-
- Assert.NotNull(del);
- Assert.Throws<NullReferenceException>(del);
- }
-
- [Theory]
- [InlineData("")]
- [InlineData("a")]
- [InlineData("\0")]
- [InlineData("abc")]
- public static unsafe void ImplicitCast_ResultingSpanMatches(string s)
- {
- ReadOnlySpan<char> span = s;
- Assert.Equal(s.Length, span.Length);
- fixed (char* stringPtr = s)
- fixed (char* spanPtr = &MemoryMarshal.GetReference(span))
- {
- Assert.Equal((IntPtr)stringPtr, (IntPtr)spanPtr);
- }
- }
-
- [Fact]
- public static void ImplicitCast_NullString_ReturnsDefaultSpan()
- {
- ReadOnlySpan<char> span = (string)null;
- Assert.True(span == default);
- }
-
- [Theory]
- [InlineData("Hello", 'l', StringComparison.Ordinal, 2)]
- [InlineData("Hello", 'x', StringComparison.Ordinal, -1)]
- [InlineData("Hello", 'h', StringComparison.Ordinal, -1)]
- [InlineData("Hello", 'o', StringComparison.Ordinal, 4)]
- [InlineData("Hello", 'h', StringComparison.OrdinalIgnoreCase, 0)]
- [InlineData("HelLo", 'L', StringComparison.OrdinalIgnoreCase, 2)]
- [InlineData("HelLo", 'L', StringComparison.Ordinal, 3)]
- [InlineData("HelLo", '\0', StringComparison.Ordinal, -1)]
- [InlineData("!@#$%", '%', StringComparison.Ordinal, 4)]
- [InlineData("!@#$", '!', StringComparison.Ordinal, 0)]
- [InlineData("!@#$", '@', StringComparison.Ordinal, 1)]
- [InlineData("!@#$%", '%', StringComparison.OrdinalIgnoreCase, 4)]
- [InlineData("!@#$", '!', StringComparison.OrdinalIgnoreCase, 0)]
- [InlineData("!@#$", '@', StringComparison.OrdinalIgnoreCase, 1)]
- [InlineData("_____________\u807f", '\u007f', StringComparison.Ordinal, -1)]
- [InlineData("_____________\u807f__", '\u007f', StringComparison.Ordinal, -1)]
- [InlineData("_____________\u807f\u007f_", '\u007f', StringComparison.Ordinal, 14)]
- [InlineData("__\u807f_______________", '\u007f', StringComparison.Ordinal, -1)]
- [InlineData("__\u807f___\u007f___________", '\u007f', StringComparison.Ordinal, 6)]
- [InlineData("_____________\u807f", '\u007f', StringComparison.OrdinalIgnoreCase, -1)]
- [InlineData("_____________\u807f__", '\u007f', StringComparison.OrdinalIgnoreCase, -1)]
- [InlineData("_____________\u807f\u007f_", '\u007f', StringComparison.OrdinalIgnoreCase, 14)]
- [InlineData("__\u807f_______________", '\u007f', StringComparison.OrdinalIgnoreCase, -1)]
- [InlineData("__\u807f___\u007f___________", '\u007f', StringComparison.OrdinalIgnoreCase, 6)]
- public static void IndexOf_SingleLetter(string s, char target, StringComparison stringComparison, int expected)
- {
- Assert.Equal(expected, s.IndexOf(target, stringComparison));
- var charArray = new char[1];
- charArray[0] = target;
- Assert.Equal(expected, s.AsSpan().IndexOf(charArray, stringComparison));
- }
-
- [Fact]
- public static void IndexOf_TurkishI_TurkishCulture_Char()
- {
- using (new ThreadCultureChange("tr-TR"))
- {
- string s = "Turkish I \u0131s TROUBL\u0130NG!";
- char value = '\u0130';
- Assert.Equal(19, s.IndexOf(value));
- Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(4, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal(19, s.IndexOf(value, StringComparison.Ordinal));
- Assert.Equal(19, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
-
- ReadOnlySpan<char> span = s.AsSpan();
- Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.CurrentCulture));
- Assert.Equal(4, span.IndexOf(new char[] { value }, StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.Ordinal));
- Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.OrdinalIgnoreCase));
-
- value = '\u0131';
- Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
- Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
-
- Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.CurrentCulture));
- Assert.Equal(8, span.IndexOf(new char[] { value }, StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.Ordinal));
- Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.OrdinalIgnoreCase));
- }
- }
-
- [Fact]
- public static void IndexOf_TurkishI_InvariantCulture_Char()
- {
- using (new ThreadCultureChange(CultureInfo.InvariantCulture))
- {
- string s = "Turkish I \u0131s TROUBL\u0130NG!";
- char value = '\u0130';
-
- Assert.Equal(19, s.IndexOf(value));
- Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
-
- value = '\u0131';
- Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- }
- }
-
- [Fact]
- public static void IndexOf_TurkishI_EnglishUSCulture_Char()
- {
- using (new ThreadCultureChange("en-US"))
- {
- string s = "Turkish I \u0131s TROUBL\u0130NG!";
- char value = '\u0130';
-
- Assert.Equal(19, s.IndexOf(value));
- Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
-
- value = '\u0131';
- Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- }
- }
-
- [Fact]
- public static void IndexOf_EquivalentDiacritics_EnglishUSCulture_Char()
- {
- string s = "Exhibit a\u0300\u00C0";
- char value = '\u00C0';
-
- using (new ThreadCultureChange("en-US"))
- {
- Assert.Equal(10, s.IndexOf(value));
- Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
- Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
- }
- }
-
- [Fact]
- public static void IndexOf_EquivalentDiacritics_InvariantCulture_Char()
- {
- string s = "Exhibit a\u0300\u00C0";
- char value = '\u00C0';
-
- using (new ThreadCultureChange(CultureInfo.InvariantCulture))
- {
- Assert.Equal(10, s.IndexOf(value));
- Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- }
- }
-
- [Fact]
- public static void IndexOf_CyrillicE_EnglishUSCulture_Char()
- {
- string s = "Foo\u0400Bar";
- char value = '\u0400';
-
- using (new ThreadCultureChange("en-US"))
- {
- Assert.Equal(3, s.IndexOf(value));
- Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- Assert.Equal(3, s.IndexOf(value, StringComparison.Ordinal));
- Assert.Equal(3, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
- }
- }
-
- [Fact]
- public static void IndexOf_CyrillicE_InvariantCulture_Char()
- {
- string s = "Foo\u0400Bar";
- char value = '\u0400';
-
- using (new ThreadCultureChange(CultureInfo.InvariantCulture))
- {
- Assert.Equal(3, s.IndexOf(value));
- Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCulture));
- Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
- }
- }
-
- [Fact]
- public static void IndexOf_Invalid_Char()
- {
- // Invalid comparison type
- AssertExtensions.Throws<ArgumentException>("comparisonType", () => "foo".IndexOf('o', StringComparison.CurrentCulture - 1));
- AssertExtensions.Throws<ArgumentException>("comparisonType", () => "foo".IndexOf('o', StringComparison.OrdinalIgnoreCase + 1));
- }
-
- [Theory]
- [MemberData(nameof(Concat_Strings_2_3_4_TestData))]
- public static void Concat_Spans(string[] values, string expected)
- {
- Assert.InRange(values.Length, 2, 4);
-
- string result =
- values.Length == 2 ? string.Concat(values[0].AsSpan(), values[1].AsSpan()) :
- values.Length == 3 ? string.Concat(values[0].AsSpan(), values[1].AsSpan(), values[2].AsSpan()) :
- string.Concat(values[0].AsSpan(), values[1].AsSpan(), values[2].AsSpan(), values[3].AsSpan());
-
- if (result.Length == 0)
- {
- Assert.Same(string.Empty, result);
- }
-
- Assert.Equal(expected, result);
- }
-
- [Fact]
- public static void IndexerUsingIndexTest()
- {
- Index index;
- string s = "0123456789ABCDEF";
-
- for (int i = 0; i < s.Length; i++)
- {
- index = Index.FromStart(i);
- Assert.Equal(s[i], s[index]);
-
- index = Index.FromEnd(i + 1);
- Assert.Equal(s[s.Length - i - 1], s[index]);
- }
-
- index = Index.FromStart(s.Length + 1);
- char c;
- Assert.Throws<IndexOutOfRangeException>(() => c = s[index]);
-
- index = Index.FromEnd(s.Length + 1);
- Assert.Throws<IndexOutOfRangeException>(() => c = s[index]);
- }
-
- [Fact]
- public static void IndexerUsingRangeTest()
- {
- Range range;
- string s = "0123456789ABCDEF";
-
- for (int i = 0; i < s.Length; i++)
- {
- range = new Range(Index.FromStart(0), Index.FromStart(i));
- Assert.Equal(s.Substring(0, i), s[range]);
-
- range = new Range(Index.FromEnd(s.Length), Index.FromEnd(i));
- Assert.Equal(s.Substring(0, s.Length - i), s[range]);
- }
-
- range = new Range(Index.FromStart(s.Length - 2), Index.FromStart(s.Length + 1));
- string s1;
- Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
-
- range = new Range(Index.FromEnd(s.Length + 1), Index.FromEnd(0));
- Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
- }
-
- [Fact]
- public static void SubstringUsingIndexTest()
- {
- string s = "0123456789ABCDEF";
-
- for (int i = 0; i < s.Length; i++)
- {
- Assert.Equal(s.Substring(i), s[i..]);
- Assert.Equal(s.Substring(s.Length - i - 1), s[^(i + 1)..]);
- }
-
- // String.Substring allows the string length as a valid input.
- Assert.Equal(s.Substring(s.Length), s[s.Length..]);
-
- Assert.Throws<ArgumentOutOfRangeException>(() => s[(s.Length + 1)..]);
- Assert.Throws<ArgumentOutOfRangeException>(() => s[^(s.Length + 1)..]);
- }
-
- [Fact]
- public static void SubstringUsingRangeTest()
- {
- string s = "0123456789ABCDEF";
- Range range;
-
- for (int i = 0; i < s.Length; i++)
- {
- range = new Range(Index.FromStart(0), Index.FromStart(i));
- Assert.Equal(s.Substring(0, i), s[range]);
-
- range = new Range(Index.FromEnd(s.Length), Index.FromEnd(i));
- Assert.Equal(s.Substring(0, s.Length - i), s[range]);
- }
-
- range = new Range(Index.FromStart(s.Length - 2), Index.FromStart(s.Length + 1));
- string s1;
- Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
-
- range = new Range(Index.FromEnd(s.Length + 1), Index.FromEnd(0));
- Assert.Throws<ArgumentOutOfRangeException>(() => s1 = s[range]);
- }
-
- /// <summary>
- /// Returns true only if U+0020 SPACE is represented as the single byte 0x20 in the active code page.
- /// </summary>
- public static unsafe bool IsSimpleActiveCodePage
- {
- get
- {
- IntPtr pAnsiStr = IntPtr.Zero;
- try
- {
- pAnsiStr = Marshal.StringToHGlobalAnsi(" ");
- return ((byte*)pAnsiStr)[0] == (byte)' ' && ((byte*)pAnsiStr)[1] == (byte)'\0';
- }
- finally
- {
- if (pAnsiStr != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(pAnsiStr);
- }
- }
- }
- }
-
- [Theory]
- [InlineData(" Hello ", "Hello")]
- [InlineData(" \t ", "")]
- [InlineData("", "")]
- [InlineData(" ", "")]
- public static void Trim_Memory(string s, string expected)
- {
- Assert.Equal(expected, s.AsSpan().Trim().ToString()); // ReadOnlySpan
- Assert.Equal(expected, new Span<char>(s.ToCharArray()).Trim().ToString());
- Assert.Equal(expected, new Memory<char>(s.ToCharArray()).Trim().ToString());
- Assert.Equal(expected, s.AsMemory().Trim().ToString()); // ReadOnlyMemory
- }
-
- [Theory]
- [InlineData(" Hello ", " Hello")]
- [InlineData(" \t ", "")]
- [InlineData("", "")]
- [InlineData(" ", "")]
- public static void TrimEnd_Memory(string s, string expected)
- {
- Assert.Equal(expected, s.AsSpan().TrimEnd().ToString()); // ReadOnlySpan
- Assert.Equal(expected, new Span<char>(s.ToCharArray()).TrimEnd().ToString());
- Assert.Equal(expected, new Memory<char>(s.ToCharArray()).TrimEnd().ToString());
- Assert.Equal(expected, s.AsMemory().TrimEnd().ToString()); // ReadOnlyMemory
- }
-
- [Theory]
- [InlineData(" Hello ", "Hello ")]
- [InlineData(" \t ", "")]
- [InlineData("", "")]
- [InlineData(" ", "")]
- public static void TrimStart_Memory(string s, string expected)
- {
- Assert.Equal(expected, s.AsSpan().TrimStart().ToString()); // ReadOnlySpan
- Assert.Equal(expected, new Span<char>(s.ToCharArray()).TrimStart().ToString());
- Assert.Equal(expected, new Memory<char>(s.ToCharArray()).TrimStart().ToString());
- Assert.Equal(expected, s.AsMemory().TrimStart().ToString()); // ReadOnlyMemory
- }
-
- [Fact]
- public static void ZeroLengthTrim_Memory()
- {
- string s1 = string.Empty;
-
- ReadOnlySpan<char> ros = s1.AsSpan();
- Assert.True(ros.SequenceEqual(ros.Trim()));
- Assert.True(ros.SequenceEqual(ros.TrimStart()));
- Assert.True(ros.SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(s1.ToCharArray());
- Assert.True(span.SequenceEqual(span.Trim()));
- Assert.True(span.SequenceEqual(span.TrimStart()));
- Assert.True(span.SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(s1.ToCharArray());
- Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(s1.ToCharArray());
- Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
- }
-
- [Fact]
- public static void NoWhiteSpaceTrim_Memory()
- {
- for (int length = 0; length < 32; length++)
- {
- char[] a = new char[length];
- for (int i = 0; i < length; i++)
- {
- a[i] = 'a';
- }
- string s1 = new string(a);
-
- ReadOnlySpan<char> ros = s1.AsSpan();
- Assert.True(ros.SequenceEqual(ros.Trim()));
- Assert.True(ros.SequenceEqual(ros.TrimStart()));
- Assert.True(ros.SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(a);
- Assert.True(span.SequenceEqual(span.Trim()));
- Assert.True(span.SequenceEqual(span.TrimStart()));
- Assert.True(span.SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(a);
- Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
- Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
- }
- }
-
- [Fact]
- public static void OnlyWhiteSpaceTrim_Memory()
- {
- for (int length = 0; length < 32; length++)
- {
- char[] a = new char[length];
- for (int i = 0; i < length; i++)
- {
- a[i] = ' ';
- }
- string s1 = new string(a);
-
- ReadOnlySpan<char> ros = new ReadOnlySpan<char>(a);
- Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(ros.Trim()));
- Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(ros.TrimStart()));
- Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(a);
- Assert.True(Span<char>.Empty.SequenceEqual(span.Trim()));
- Assert.True(Span<char>.Empty.SequenceEqual(span.TrimStart()));
- Assert.True(Span<char>.Empty.SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(a);
- Assert.True(Memory<char>.Empty.Span.SequenceEqual(mem.Trim().Span));
- Assert.True(Memory<char>.Empty.Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(Memory<char>.Empty.Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
- Assert.True(ReadOnlyMemory<char>.Empty.Span.SequenceEqual(rom.Trim().Span));
- Assert.True(ReadOnlyMemory<char>.Empty.Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(ReadOnlyMemory<char>.Empty.Span.SequenceEqual(rom.TrimEnd().Span));
- }
- }
-
- [Fact]
- public static void WhiteSpaceAtStartTrim_Memory()
- {
- for (int length = 2; length < 32; length++)
- {
- char[] a = new char[length];
- for (int i = 0; i < length; i++)
- {
- a[i] = 'a';
- }
- a[0] = ' ';
- string s1 = new string(a);
-
- ReadOnlySpan<char> ros = s1.AsSpan();
- Assert.True(ros.Slice(1).SequenceEqual(ros.Trim()));
- Assert.True(ros.Slice(1).SequenceEqual(ros.TrimStart()));
- Assert.True(ros.SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(a);
- Assert.True(span.Slice(1).SequenceEqual(span.Trim()));
- Assert.True(span.Slice(1).SequenceEqual(span.TrimStart()));
- Assert.True(span.SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(a);
- Assert.True(mem.Slice(1).Span.SequenceEqual(mem.Trim().Span));
- Assert.True(mem.Slice(1).Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
- Assert.True(rom.Slice(1).Span.SequenceEqual(rom.Trim().Span));
- Assert.True(rom.Slice(1).Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
- }
- }
-
- [Fact]
- public static void WhiteSpaceAtEndTrim_Memory()
- {
- for (int length = 2; length < 32; length++)
- {
- char[] a = new char[length];
- for (int i = 0; i < length; i++)
- {
- a[i] = 'a';
- }
- a[length - 1] = ' ';
- string s1 = new string(a);
-
- ReadOnlySpan<char> ros = s1.AsSpan();
- Assert.True(ros.Slice(0, length - 1).SequenceEqual(ros.Trim()));
- Assert.True(ros.SequenceEqual(ros.TrimStart()));
- Assert.True(ros.Slice(0, length - 1).SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(a);
- Assert.True(span.Slice(0, length - 1).SequenceEqual(span.Trim()));
- Assert.True(span.SequenceEqual(span.TrimStart()));
- Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(a);
- Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(mem.Trim().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
- Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(rom.Trim().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(rom.TrimEnd().Span));
- }
- }
-
- [Fact]
- public static void WhiteSpaceAtStartAndEndTrim_Memory()
- {
- for (int length = 3; length < 32; length++)
- {
- char[] a = new char[length];
- for (int i = 0; i < length; i++)
- {
- a[i] = 'a';
- }
- a[0] = ' ';
- a[length - 1] = ' ';
- string s1 = new string(a);
-
- ReadOnlySpan<char> ros = s1.AsSpan();
- Assert.True(ros.Slice(1, length - 2).SequenceEqual(ros.Trim()));
- Assert.True(ros.Slice(1).SequenceEqual(ros.TrimStart()));
- Assert.True(ros.Slice(0, length - 1).SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(a);
- Assert.True(span.Slice(1, length - 2).SequenceEqual(span.Trim()));
- Assert.True(span.Slice(1).SequenceEqual(span.TrimStart()));
- Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(a);
- Assert.True(mem.Slice(1, length - 2).Span.SequenceEqual(mem.Trim().Span));
- Assert.True(mem.Slice(1).Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
- Assert.True(rom.Slice(1, length - 2).Span.SequenceEqual(rom.Trim().Span));
- Assert.True(rom.Slice(1).Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(rom.TrimEnd().Span));
- }
- }
-
- [Fact]
- public static void WhiteSpaceInMiddleTrim_Memory()
- {
- for (int length = 3; length < 32; length++)
- {
- char[] a = new char[length];
- for (int i = 0; i < length; i++)
- {
- a[i] = 'a';
- }
- a[1] = ' ';
- string s1 = new string(a);
-
- ReadOnlySpan<char> ros = s1.AsSpan();
- Assert.True(ros.SequenceEqual(ros.Trim()));
- Assert.True(ros.SequenceEqual(ros.TrimStart()));
- Assert.True(ros.SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(a);
- Assert.True(span.SequenceEqual(span.Trim()));
- Assert.True(span.SequenceEqual(span.TrimStart()));
- Assert.True(span.SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(a);
- Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
- Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
- }
- }
-
- [Fact]
- public static void TrimWhiteSpaceMultipleTimes_Memory()
- {
- for (int length = 3; length < 32; length++)
- {
- char[] a = new char[length];
- for (int i = 0; i < length; i++)
- {
- a[i] = 'a';
- }
- a[0] = ' ';
- a[length - 1] = ' ';
- string s1 = new string(a);
-
- // ReadOnlySpan
- {
- ReadOnlySpan<char> ros = s1.AsSpan();
- ReadOnlySpan<char> trimResult = ros.Trim();
- ReadOnlySpan<char> trimStartResult = ros.TrimStart();
- ReadOnlySpan<char> trimEndResult = ros.TrimEnd();
- Assert.True(ros.Slice(1, length - 2).SequenceEqual(trimResult));
- Assert.True(ros.Slice(1).SequenceEqual(trimStartResult));
- Assert.True(ros.Slice(0, length - 1).SequenceEqual(trimEndResult));
-
- // 2nd attempt should do nothing
- Assert.True(trimResult.SequenceEqual(trimResult.Trim()));
- Assert.True(trimStartResult.SequenceEqual(trimStartResult.TrimStart()));
- Assert.True(trimEndResult.SequenceEqual(trimEndResult.TrimEnd()));
- }
-
- // Span
- {
- Span<char> span = new Span<char>(a);
- Span<char> trimResult = span.Trim();
- Span<char> trimStartResult = span.TrimStart();
- Span<char> trimEndResult = span.TrimEnd();
- Assert.True(span.Slice(1, length - 2).SequenceEqual(trimResult));
- Assert.True(span.Slice(1).SequenceEqual(trimStartResult));
- Assert.True(span.Slice(0, length - 1).SequenceEqual(trimEndResult));
-
- // 2nd attempt should do nothing
- Assert.True(trimResult.SequenceEqual(trimResult.Trim()));
- Assert.True(trimStartResult.SequenceEqual(trimStartResult.TrimStart()));
- Assert.True(trimEndResult.SequenceEqual(trimEndResult.TrimEnd()));
- }
-
- // Memory
- {
- Memory<char> mem = new Memory<char>(a);
- Memory<char> trimResult = mem.Trim();
- Memory<char> trimStartResult = mem.TrimStart();
- Memory<char> trimEndResult = mem.TrimEnd();
- Assert.True(mem.Slice(1, length - 2).Span.SequenceEqual(trimResult.Span));
- Assert.True(mem.Slice(1).Span.SequenceEqual(trimStartResult.Span));
- Assert.True(mem.Slice(0, length - 1).Span.SequenceEqual(trimEndResult.Span));
-
- // 2nd attempt should do nothing
- Assert.True(trimResult.Span.SequenceEqual(trimResult.Trim().Span));
- Assert.True(trimStartResult.Span.SequenceEqual(trimStartResult.TrimStart().Span));
- Assert.True(trimEndResult.Span.SequenceEqual(trimEndResult.TrimEnd().Span));
- }
-
- // ReadOnlyMemory
- {
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(a);
- ReadOnlyMemory<char> trimResult = rom.Trim();
- ReadOnlyMemory<char> trimStartResult = rom.TrimStart();
- ReadOnlyMemory<char> trimEndResult = rom.TrimEnd();
- Assert.True(rom.Slice(1, length - 2).Span.SequenceEqual(trimResult.Span));
- Assert.True(rom.Slice(1).Span.SequenceEqual(trimStartResult.Span));
- Assert.True(rom.Slice(0, length - 1).Span.SequenceEqual(trimEndResult.Span));
-
- // 2nd attempt should do nothing
- Assert.True(trimResult.Span.SequenceEqual(trimResult.Trim().Span));
- Assert.True(trimStartResult.Span.SequenceEqual(trimStartResult.TrimStart().Span));
- Assert.True(trimEndResult.Span.SequenceEqual(trimEndResult.TrimEnd().Span));
- }
- }
- }
-
- [Fact]
- public static void MakeSureNoTrimChecksGoOutOfRange_Memory()
- {
- for (int length = 3; length < 64; length++)
- {
- char[] first = new char[length];
- first[0] = ' ';
- first[length - 1] = ' ';
- string s1 = new string(first, 1, length - 2);
-
- ReadOnlySpan<char> ros = s1.AsSpan();
- Assert.True(ros.SequenceEqual(ros.Trim()));
- Assert.True(ros.SequenceEqual(ros.TrimStart()));
- Assert.True(ros.SequenceEqual(ros.TrimEnd()));
-
- Span<char> span = new Span<char>(s1.ToCharArray());
- Assert.True(span.SequenceEqual(span.Trim()));
- Assert.True(span.SequenceEqual(span.TrimStart()));
- Assert.True(span.SequenceEqual(span.TrimEnd()));
-
- Memory<char> mem = new Memory<char>(s1.ToCharArray());
- Assert.True(mem.Span.SequenceEqual(mem.Trim().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimStart().Span));
- Assert.True(mem.Span.SequenceEqual(mem.TrimEnd().Span));
-
- ReadOnlyMemory<char> rom = new ReadOnlyMemory<char>(s1.ToCharArray());
- Assert.True(rom.Span.SequenceEqual(rom.Trim().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimStart().Span));
- Assert.True(rom.Span.SequenceEqual(rom.TrimEnd().Span));
- }
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Numerics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using Xunit;
+
+namespace System.Text.Tests
+{
+ // Since many of the methods we'll be testing are internal, we'll need to invoke
+ // them via reflection.
+ public static unsafe class AsciiUtilityTests
+ {
+ private const int SizeOfVector128 = 128 / 8;
+
+ // The delegate definitions and members below provide us access to CoreLib's internals.
+ // We use UIntPtr instead of nuint everywhere here since we don't know what our target arch is.
+
+ private delegate UIntPtr FnGetIndexOfFirstNonAsciiByte(byte* pBuffer, UIntPtr bufferLength);
+ private static readonly UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiByte> _fnGetIndexOfFirstNonAsciiByte = new UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiByte>("GetIndexOfFirstNonAsciiByte");
+
+ private delegate UIntPtr FnGetIndexOfFirstNonAsciiChar(char* pBuffer, UIntPtr bufferLength);
+ private static readonly UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiChar> _fnGetIndexOfFirstNonAsciiChar = new UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiChar>("GetIndexOfFirstNonAsciiChar");
+
+ private delegate UIntPtr FnNarrowUtf16ToAscii(char* pUtf16Buffer, byte* pAsciiBuffer, UIntPtr elementCount);
+ private static readonly UnsafeLazyDelegate<FnNarrowUtf16ToAscii> _fnNarrowUtf16ToAscii = new UnsafeLazyDelegate<FnNarrowUtf16ToAscii>("NarrowUtf16ToAscii");
+
+ private delegate UIntPtr FnWidenAsciiToUtf16(byte* pAsciiBuffer, char* pUtf16Buffer, UIntPtr elementCount);
+ private static readonly UnsafeLazyDelegate<FnWidenAsciiToUtf16> _fnWidenAsciiToUtf16 = new UnsafeLazyDelegate<FnWidenAsciiToUtf16>("WidenAsciiToUtf16");
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiByte_EmptyInput_NullReference()
+ {
+ Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiByte.Delegate(null, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiByte_EmptyInput_NonNullReference()
+ {
+ byte b = default;
+ Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiByte.Delegate(&b, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiByte_Vector128InnerLoop()
+ {
+ // The purpose of this test is to make sure we're identifying the correct
+ // vector (of the two that we're reading simultaneously) when performing
+ // the final ASCII drain at the end of the method once we've broken out
+ // of the inner loop.
+
+ using (BoundedMemory<byte> mem = BoundedMemory.Allocate<byte>(1024))
+ {
+ Span<byte> bytes = mem.Span;
+
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ bytes[i] &= 0x7F; // make sure each byte (of the pre-populated random data) is ASCII
+ }
+
+ // Two vectors have offsets 0 .. 31. We'll go backward to avoid having to
+ // re-clear the vector every time.
+
+ for (int i = 2 * SizeOfVector128 - 1; i >= 0; i--)
+ {
+ bytes[100 + i * 13] = 0x80; // 13 is relatively prime to 32, so it ensures all possible positions are hit
+ Assert.Equal(100 + i * 13, CallGetIndexOfFirstNonAsciiByte(bytes));
+ }
+ }
+ }
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiByte_Boundaries()
+ {
+ // The purpose of this test is to make sure we're hitting all of the vectorized
+ // and draining logic correctly both in the SSE2 and in the non-SSE2 enlightened
+ // code paths. We shouldn't be reading beyond the boundaries we were given.
+
+ // The 5 * Vector test should make sure that we're exercising all possible
+ // code paths across both implementations.
+ using (BoundedMemory<byte> mem = BoundedMemory.Allocate<byte>(5 * Vector<byte>.Count))
+ {
+ Span<byte> bytes = mem.Span;
+
+ // First, try it with all-ASCII buffers.
+
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ bytes[i] &= 0x7F; // make sure each byte (of the pre-populated random data) is ASCII
+ }
+
+ for (int i = bytes.Length; i >= 0; i--)
+ {
+ Assert.Equal(i, CallGetIndexOfFirstNonAsciiByte(bytes.Slice(0, i)));
+ }
+
+ // Then, try it with non-ASCII bytes.
+
+ for (int i = bytes.Length; i >= 1; i--)
+ {
+ bytes[i - 1] = 0x80; // set non-ASCII
+ Assert.Equal(i - 1, CallGetIndexOfFirstNonAsciiByte(bytes.Slice(0, i)));
+ }
+ }
+ }
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiChar_EmptyInput_NullReference()
+ {
+ Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiChar.Delegate(null, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiChar_EmptyInput_NonNullReference()
+ {
+ char c = default;
+ Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiChar.Delegate(&c, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiChar_Vector128InnerLoop()
+ {
+ // The purpose of this test is to make sure we're identifying the correct
+ // vector (of the two that we're reading simultaneously) when performing
+ // the final ASCII drain at the end of the method once we've broken out
+ // of the inner loop.
+ //
+ // Use U+0123 instead of U+0080 for this test because if our implementation
+ // uses pminuw / pmovmskb incorrectly, U+0123 will incorrectly show up as ASCII,
+ // causing our test to produce a false negative.
+
+ using (BoundedMemory<char> mem = BoundedMemory.Allocate<char>(1024))
+ {
+ Span<char> chars = mem.Span;
+
+ for (int i = 0; i < chars.Length; i++)
+ {
+ chars[i] &= '\u007F'; // make sure each char (of the pre-populated random data) is ASCII
+ }
+
+ // Two vectors have offsets 0 .. 31. We'll go backward to avoid having to
+ // re-clear the vector every time.
+
+ for (int i = 2 * SizeOfVector128 - 1; i >= 0; i--)
+ {
+ chars[100 + i * 13] = '\u0123'; // 13 is relatively prime to 32, so it ensures all possible positions are hit
+ Assert.Equal(100 + i * 13, CallGetIndexOfFirstNonAsciiChar(chars));
+ }
+ }
+ }
+
+ [Fact]
+ public static void GetIndexOfFirstNonAsciiChar_Boundaries()
+ {
+ // The purpose of this test is to make sure we're hitting all of the vectorized
+ // and draining logic correctly both in the SSE2 and in the non-SSE2 enlightened
+ // code paths. We shouldn't be reading beyond the boundaries we were given.
+ //
+ // The 5 * Vector test should make sure that we're exercising all possible
+ // code paths across both implementations. The sizeof(char) is because we're
+ // specifying element count, but underlying implementation reintepret casts to bytes.
+ //
+ // Use U+0123 instead of U+0080 for this test because if our implementation
+ // uses pminuw / pmovmskb incorrectly, U+0123 will incorrectly show up as ASCII,
+ // causing our test to produce a false negative.
+
+ using (BoundedMemory<char> mem = BoundedMemory.Allocate<char>(5 * Vector<byte>.Count / sizeof(char)))
+ {
+ Span<char> chars = mem.Span;
+
+ for (int i = 0; i < chars.Length; i++)
+ {
+ chars[i] &= '\u007F'; // make sure each char (of the pre-populated random data) is ASCII
+ }
+
+ for (int i = chars.Length; i >= 0; i--)
+ {
+ Assert.Equal(i, CallGetIndexOfFirstNonAsciiChar(chars.Slice(0, i)));
+ }
+
+ // Then, try it with non-ASCII bytes.
+
+ for (int i = chars.Length; i >= 1; i--)
+ {
+ chars[i - 1] = '\u0123'; // set non-ASCII
+ Assert.Equal(i - 1, CallGetIndexOfFirstNonAsciiChar(chars.Slice(0, i)));
+ }
+ }
+ }
+
+ [Fact]
+ public static void WidenAsciiToUtf16_EmptyInput_NullReferences()
+ {
+ Assert.Equal(UIntPtr.Zero, _fnWidenAsciiToUtf16.Delegate(null, null, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void WidenAsciiToUtf16_EmptyInput_NonNullReference()
+ {
+ byte b = default;
+ char c = default;
+ Assert.Equal(UIntPtr.Zero, _fnWidenAsciiToUtf16.Delegate(&b, &c, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void WidenAsciiToUtf16_AllAsciiInput()
+ {
+ using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
+ using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
+
+ // Fill source with 00 .. 7F, then trap future writes.
+
+ Span<byte> asciiSpan = asciiMem.Span;
+ for (int i = 0; i < asciiSpan.Length; i++)
+ {
+ asciiSpan[i] = (byte)i;
+ }
+ asciiMem.MakeReadonly();
+
+ // We'll write to the UTF-16 span.
+ // We test with a variety of span lengths to test alignment and fallthrough code paths.
+
+ Span<char> utf16Span = utf16Mem.Span;
+
+ for (int i = 0; i < asciiSpan.Length; i++)
+ {
+ utf16Span.Clear(); // remove any data from previous iteration
+
+ // First, validate that the workhorse saw the incoming data as all-ASCII.
+
+ Assert.Equal(128 - i, CallWidenAsciiToUtf16(asciiSpan.Slice(i), utf16Span.Slice(i)));
+
+ // Then, validate that the data was transcoded properly.
+
+ for (int j = i; j < 128; j++)
+ {
+ Assert.Equal((ushort)asciiSpan[i], (ushort)utf16Span[i]);
+ }
+ }
+ }
+
+ [Fact]
+ public static void WidenAsciiToUtf16_SomeNonAsciiInput()
+ {
+ using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
+ using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
+
+ // Fill source with 00 .. 7F, then trap future writes.
+
+ Span<byte> asciiSpan = asciiMem.Span;
+ for (int i = 0; i < asciiSpan.Length; i++)
+ {
+ asciiSpan[i] = (byte)i;
+ }
+
+ // We'll write to the UTF-16 span.
+
+ Span<char> utf16Span = utf16Mem.Span;
+
+ for (int i = asciiSpan.Length - 1; i >= 0; i--)
+ {
+ RandomNumberGenerator.Fill(MemoryMarshal.Cast<char, byte>(utf16Span)); // fill with garbage
+
+ // First, keep track of the garbage we wrote to the destination.
+ // We want to ensure it wasn't overwritten.
+
+ char[] expectedTrailingData = utf16Span.Slice(i).ToArray();
+
+ // Then, set the desired byte as non-ASCII, then check that the workhorse
+ // correctly saw the data as non-ASCII.
+
+ asciiSpan[i] |= (byte)0x80;
+ Assert.Equal(i, CallWidenAsciiToUtf16(asciiSpan, utf16Span));
+
+ // Next, validate that the ASCII data was transcoded properly.
+
+ for (int j = 0; j < i; j++)
+ {
+ Assert.Equal((ushort)asciiSpan[j], (ushort)utf16Span[j]);
+ }
+
+ // Finally, validate that the trailing data wasn't overwritten with non-ASCII data.
+
+ Assert.Equal(expectedTrailingData, utf16Span.Slice(i).ToArray());
+ }
+ }
+
+ [Fact]
+ public static unsafe void NarrowUtf16ToAscii_EmptyInput_NullReferences()
+ {
+ Assert.Equal(UIntPtr.Zero, _fnNarrowUtf16ToAscii.Delegate(null, null, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void NarrowUtf16ToAscii_EmptyInput_NonNullReference()
+ {
+ char c = default;
+ byte b = default;
+ Assert.Equal(UIntPtr.Zero, _fnNarrowUtf16ToAscii.Delegate(&c, &b, UIntPtr.Zero));
+ }
+
+ [Fact]
+ public static void NarrowUtf16ToAscii_AllAsciiInput()
+ {
+ using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
+ using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
+
+ // Fill source with 00 .. 7F.
+
+ Span<char> utf16Span = utf16Mem.Span;
+ for (int i = 0; i < utf16Span.Length; i++)
+ {
+ utf16Span[i] = (char)i;
+ }
+ utf16Mem.MakeReadonly();
+
+ // We'll write to the ASCII span.
+ // We test with a variety of span lengths to test alignment and fallthrough code paths.
+
+ Span<byte> asciiSpan = asciiMem.Span;
+
+ for (int i = 0; i < utf16Span.Length; i++)
+ {
+ asciiSpan.Clear(); // remove any data from previous iteration
+
+ // First, validate that the workhorse saw the incoming data as all-ASCII.
+
+ Assert.Equal(128 - i, CallNarrowUtf16ToAscii(utf16Span.Slice(i), asciiSpan.Slice(i)));
+
+ // Then, validate that the data was transcoded properly.
+
+ for (int j = i; j < 128; j++)
+ {
+ Assert.Equal((ushort)utf16Span[i], (ushort)asciiSpan[i]);
+ }
+ }
+ }
+
+ [Fact]
+ public static void NarrowUtf16ToAscii_SomeNonAsciiInput()
+ {
+ using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
+ using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
+
+ // Fill source with 00 .. 7F.
+
+ Span<char> utf16Span = utf16Mem.Span;
+ for (int i = 0; i < utf16Span.Length; i++)
+ {
+ utf16Span[i] = (char)i;
+ }
+
+ // We'll write to the ASCII span.
+
+ Span<byte> asciiSpan = asciiMem.Span;
+
+ for (int i = utf16Span.Length - 1; i >= 0; i--)
+ {
+ RandomNumberGenerator.Fill(asciiSpan); // fill with garbage
+
+ // First, keep track of the garbage we wrote to the destination.
+ // We want to ensure it wasn't overwritten.
+
+ byte[] expectedTrailingData = asciiSpan.Slice(i).ToArray();
+
+ // Then, set the desired byte as non-ASCII, then check that the workhorse
+ // correctly saw the data as non-ASCII.
+
+ utf16Span[i] = '\u0123'; // use U+0123 instead of U+0080 since it catches inappropriate pmovmskb usage
+ Assert.Equal(i, CallNarrowUtf16ToAscii(utf16Span, asciiSpan));
+
+ // Next, validate that the ASCII data was transcoded properly.
+
+ for (int j = 0; j < i; j++)
+ {
+ Assert.Equal((ushort)utf16Span[j], (ushort)asciiSpan[j]);
+ }
+
+ // Finally, validate that the trailing data wasn't overwritten with non-ASCII data.
+
+ Assert.Equal(expectedTrailingData, asciiSpan.Slice(i).ToArray());
+ }
+ }
+
+ private static int CallGetIndexOfFirstNonAsciiByte(ReadOnlySpan<byte> buffer)
+ {
+ fixed (byte* pBuffer = &MemoryMarshal.GetReference(buffer))
+ {
+ // Conversions between UIntPtr <-> int are not checked by default.
+ return checked((int)_fnGetIndexOfFirstNonAsciiByte.Delegate(pBuffer, (UIntPtr)buffer.Length));
+ }
+ }
+
+ private static int CallGetIndexOfFirstNonAsciiChar(ReadOnlySpan<char> buffer)
+ {
+ fixed (char* pBuffer = &MemoryMarshal.GetReference(buffer))
+ {
+ // Conversions between UIntPtr <-> int are not checked by default.
+ return checked((int)_fnGetIndexOfFirstNonAsciiChar.Delegate(pBuffer, (UIntPtr)buffer.Length));
+ }
+ }
+
+ private static int CallNarrowUtf16ToAscii(ReadOnlySpan<char> utf16, Span<byte> ascii)
+ {
+ Assert.Equal(utf16.Length, ascii.Length);
+
+ fixed (char* pUtf16 = &MemoryMarshal.GetReference(utf16))
+ fixed (byte* pAscii = &MemoryMarshal.GetReference(ascii))
+ {
+ // Conversions between UIntPtr <-> int are not checked by default.
+ return checked((int)_fnNarrowUtf16ToAscii.Delegate(pUtf16, pAscii, (UIntPtr)utf16.Length));
+ }
+ }
+
+ private static int CallWidenAsciiToUtf16(ReadOnlySpan<byte> ascii, Span<char> utf16)
+ {
+ Assert.Equal(ascii.Length, utf16.Length);
+
+ fixed (byte* pAscii = &MemoryMarshal.GetReference(ascii))
+ fixed (char* pUtf16 = &MemoryMarshal.GetReference(utf16))
+ {
+ // Conversions between UIntPtr <-> int are not checked by default.
+ return checked((int)_fnWidenAsciiToUtf16.Delegate(pAscii, pUtf16, (UIntPtr)ascii.Length));
+ }
+ }
+
+ private static Type GetAsciiUtilityType()
+ {
+ return typeof(object).Assembly.GetType("System.Text.ASCIIUtility");
+ }
+
+ private sealed class UnsafeLazyDelegate<TDelegate> where TDelegate : class
+ {
+ private readonly Lazy<TDelegate> _lazyDelegate;
+
+ public UnsafeLazyDelegate(string methodName)
+ {
+ _lazyDelegate = new Lazy<TDelegate>(() =>
+ {
+ Assert.True(typeof(TDelegate).IsSubclassOf(typeof(MulticastDelegate)));
+
+ // Get the MethodInfo for the target method
+
+ MethodInfo methodInfo = GetAsciiUtilityType().GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+ Assert.NotNull(methodInfo);
+
+ // Construct the TDelegate pointing to this method
+
+ return (TDelegate)Activator.CreateInstance(typeof(TDelegate), new object[] { null, methodInfo.MethodHandle.GetFunctionPointer() });
+ });
+ }
+
+ public TDelegate Delegate => _lazyDelegate.Value;
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Numerics;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography;
-using Xunit;
-
-namespace System.Text.Tests
-{
- // Since many of the methods we'll be testing are internal, we'll need to invoke
- // them via reflection.
- public static unsafe partial class AsciiUtilityTests
- {
- private const int SizeOfVector128 = 128 / 8;
-
- // The delegate definitions and members below provide us access to CoreLib's internals.
- // We use UIntPtr instead of nuint everywhere here since we don't know what our target arch is.
-
- private delegate UIntPtr FnGetIndexOfFirstNonAsciiByte(byte* pBuffer, UIntPtr bufferLength);
- private static readonly UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiByte> _fnGetIndexOfFirstNonAsciiByte = new UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiByte>("GetIndexOfFirstNonAsciiByte");
-
- private delegate UIntPtr FnGetIndexOfFirstNonAsciiChar(char* pBuffer, UIntPtr bufferLength);
- private static readonly UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiChar> _fnGetIndexOfFirstNonAsciiChar = new UnsafeLazyDelegate<FnGetIndexOfFirstNonAsciiChar>("GetIndexOfFirstNonAsciiChar");
-
- private delegate UIntPtr FnNarrowUtf16ToAscii(char* pUtf16Buffer, byte* pAsciiBuffer, UIntPtr elementCount);
- private static readonly UnsafeLazyDelegate<FnNarrowUtf16ToAscii> _fnNarrowUtf16ToAscii = new UnsafeLazyDelegate<FnNarrowUtf16ToAscii>("NarrowUtf16ToAscii");
-
- private delegate UIntPtr FnWidenAsciiToUtf16(byte* pAsciiBuffer, char* pUtf16Buffer, UIntPtr elementCount);
- private static readonly UnsafeLazyDelegate<FnWidenAsciiToUtf16> _fnWidenAsciiToUtf16 = new UnsafeLazyDelegate<FnWidenAsciiToUtf16>("WidenAsciiToUtf16");
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiByte_EmptyInput_NullReference()
- {
- Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiByte.Delegate(null, UIntPtr.Zero));
- }
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiByte_EmptyInput_NonNullReference()
- {
- byte b = default;
- Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiByte.Delegate(&b, UIntPtr.Zero));
- }
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiByte_Vector128InnerLoop()
- {
- // The purpose of this test is to make sure we're identifying the correct
- // vector (of the two that we're reading simultaneously) when performing
- // the final ASCII drain at the end of the method once we've broken out
- // of the inner loop.
-
- using (BoundedMemory<byte> mem = BoundedMemory.Allocate<byte>(1024))
- {
- Span<byte> bytes = mem.Span;
-
- for (int i = 0; i < bytes.Length; i++)
- {
- bytes[i] &= 0x7F; // make sure each byte (of the pre-populated random data) is ASCII
- }
-
- // Two vectors have offsets 0 .. 31. We'll go backward to avoid having to
- // re-clear the vector every time.
-
- for (int i = 2 * SizeOfVector128 - 1; i >= 0; i--)
- {
- bytes[100 + i * 13] = 0x80; // 13 is relatively prime to 32, so it ensures all possible positions are hit
- Assert.Equal(100 + i * 13, CallGetIndexOfFirstNonAsciiByte(bytes));
- }
- }
- }
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiByte_Boundaries()
- {
- // The purpose of this test is to make sure we're hitting all of the vectorized
- // and draining logic correctly both in the SSE2 and in the non-SSE2 enlightened
- // code paths. We shouldn't be reading beyond the boundaries we were given.
-
- // The 5 * Vector test should make sure that we're exercising all possible
- // code paths across both implementations.
- using (BoundedMemory<byte> mem = BoundedMemory.Allocate<byte>(5 * Vector<byte>.Count))
- {
- Span<byte> bytes = mem.Span;
-
- // First, try it with all-ASCII buffers.
-
- for (int i = 0; i < bytes.Length; i++)
- {
- bytes[i] &= 0x7F; // make sure each byte (of the pre-populated random data) is ASCII
- }
-
- for (int i = bytes.Length; i >= 0; i--)
- {
- Assert.Equal(i, CallGetIndexOfFirstNonAsciiByte(bytes.Slice(0, i)));
- }
-
- // Then, try it with non-ASCII bytes.
-
- for (int i = bytes.Length; i >= 1; i--)
- {
- bytes[i - 1] = 0x80; // set non-ASCII
- Assert.Equal(i - 1, CallGetIndexOfFirstNonAsciiByte(bytes.Slice(0, i)));
- }
- }
- }
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiChar_EmptyInput_NullReference()
- {
- Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiChar.Delegate(null, UIntPtr.Zero));
- }
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiChar_EmptyInput_NonNullReference()
- {
- char c = default;
- Assert.Equal(UIntPtr.Zero, _fnGetIndexOfFirstNonAsciiChar.Delegate(&c, UIntPtr.Zero));
- }
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiChar_Vector128InnerLoop()
- {
- // The purpose of this test is to make sure we're identifying the correct
- // vector (of the two that we're reading simultaneously) when performing
- // the final ASCII drain at the end of the method once we've broken out
- // of the inner loop.
- //
- // Use U+0123 instead of U+0080 for this test because if our implementation
- // uses pminuw / pmovmskb incorrectly, U+0123 will incorrectly show up as ASCII,
- // causing our test to produce a false negative.
-
- using (BoundedMemory<char> mem = BoundedMemory.Allocate<char>(1024))
- {
- Span<char> chars = mem.Span;
-
- for (int i = 0; i < chars.Length; i++)
- {
- chars[i] &= '\u007F'; // make sure each char (of the pre-populated random data) is ASCII
- }
-
- // Two vectors have offsets 0 .. 31. We'll go backward to avoid having to
- // re-clear the vector every time.
-
- for (int i = 2 * SizeOfVector128 - 1; i >= 0; i--)
- {
- chars[100 + i * 13] = '\u0123'; // 13 is relatively prime to 32, so it ensures all possible positions are hit
- Assert.Equal(100 + i * 13, CallGetIndexOfFirstNonAsciiChar(chars));
- }
- }
- }
-
- [Fact]
- public static void GetIndexOfFirstNonAsciiChar_Boundaries()
- {
- // The purpose of this test is to make sure we're hitting all of the vectorized
- // and draining logic correctly both in the SSE2 and in the non-SSE2 enlightened
- // code paths. We shouldn't be reading beyond the boundaries we were given.
- //
- // The 5 * Vector test should make sure that we're exercising all possible
- // code paths across both implementations. The sizeof(char) is because we're
- // specifying element count, but underlying implementation reintepret casts to bytes.
- //
- // Use U+0123 instead of U+0080 for this test because if our implementation
- // uses pminuw / pmovmskb incorrectly, U+0123 will incorrectly show up as ASCII,
- // causing our test to produce a false negative.
-
- using (BoundedMemory<char> mem = BoundedMemory.Allocate<char>(5 * Vector<byte>.Count / sizeof(char)))
- {
- Span<char> chars = mem.Span;
-
- for (int i = 0; i < chars.Length; i++)
- {
- chars[i] &= '\u007F'; // make sure each char (of the pre-populated random data) is ASCII
- }
-
- for (int i = chars.Length; i >= 0; i--)
- {
- Assert.Equal(i, CallGetIndexOfFirstNonAsciiChar(chars.Slice(0, i)));
- }
-
- // Then, try it with non-ASCII bytes.
-
- for (int i = chars.Length; i >= 1; i--)
- {
- chars[i - 1] = '\u0123'; // set non-ASCII
- Assert.Equal(i - 1, CallGetIndexOfFirstNonAsciiChar(chars.Slice(0, i)));
- }
- }
- }
-
- [Fact]
- public static void WidenAsciiToUtf16_EmptyInput_NullReferences()
- {
- Assert.Equal(UIntPtr.Zero, _fnWidenAsciiToUtf16.Delegate(null, null, UIntPtr.Zero));
- }
-
- [Fact]
- public static void WidenAsciiToUtf16_EmptyInput_NonNullReference()
- {
- byte b = default;
- char c = default;
- Assert.Equal(UIntPtr.Zero, _fnWidenAsciiToUtf16.Delegate(&b, &c, UIntPtr.Zero));
- }
-
- [Fact]
- public static void WidenAsciiToUtf16_AllAsciiInput()
- {
- using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
- using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
-
- // Fill source with 00 .. 7F, then trap future writes.
-
- Span<byte> asciiSpan = asciiMem.Span;
- for (int i = 0; i < asciiSpan.Length; i++)
- {
- asciiSpan[i] = (byte)i;
- }
- asciiMem.MakeReadonly();
-
- // We'll write to the UTF-16 span.
- // We test with a variety of span lengths to test alignment and fallthrough code paths.
-
- Span<char> utf16Span = utf16Mem.Span;
-
- for (int i = 0; i < asciiSpan.Length; i++)
- {
- utf16Span.Clear(); // remove any data from previous iteration
-
- // First, validate that the workhorse saw the incoming data as all-ASCII.
-
- Assert.Equal(128 - i, CallWidenAsciiToUtf16(asciiSpan.Slice(i), utf16Span.Slice(i)));
-
- // Then, validate that the data was transcoded properly.
-
- for (int j = i; j < 128; j++)
- {
- Assert.Equal((ushort)asciiSpan[i], (ushort)utf16Span[i]);
- }
- }
- }
-
- [Fact]
- public static void WidenAsciiToUtf16_SomeNonAsciiInput()
- {
- using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
- using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
-
- // Fill source with 00 .. 7F, then trap future writes.
-
- Span<byte> asciiSpan = asciiMem.Span;
- for (int i = 0; i < asciiSpan.Length; i++)
- {
- asciiSpan[i] = (byte)i;
- }
-
- // We'll write to the UTF-16 span.
-
- Span<char> utf16Span = utf16Mem.Span;
-
- for (int i = asciiSpan.Length - 1; i >= 0; i--)
- {
- RandomNumberGenerator.Fill(MemoryMarshal.Cast<char, byte>(utf16Span)); // fill with garbage
-
- // First, keep track of the garbage we wrote to the destination.
- // We want to ensure it wasn't overwritten.
-
- char[] expectedTrailingData = utf16Span.Slice(i).ToArray();
-
- // Then, set the desired byte as non-ASCII, then check that the workhorse
- // correctly saw the data as non-ASCII.
-
- asciiSpan[i] |= (byte)0x80;
- Assert.Equal(i, CallWidenAsciiToUtf16(asciiSpan, utf16Span));
-
- // Next, validate that the ASCII data was transcoded properly.
-
- for (int j = 0; j < i; j++)
- {
- Assert.Equal((ushort)asciiSpan[j], (ushort)utf16Span[j]);
- }
-
- // Finally, validate that the trailing data wasn't overwritten with non-ASCII data.
-
- Assert.Equal(expectedTrailingData, utf16Span.Slice(i).ToArray());
- }
- }
-
- [Fact]
- public static unsafe void NarrowUtf16ToAscii_EmptyInput_NullReferences()
- {
- Assert.Equal(UIntPtr.Zero, _fnNarrowUtf16ToAscii.Delegate(null, null, UIntPtr.Zero));
- }
-
- [Fact]
- public static void NarrowUtf16ToAscii_EmptyInput_NonNullReference()
- {
- char c = default;
- byte b = default;
- Assert.Equal(UIntPtr.Zero, _fnNarrowUtf16ToAscii.Delegate(&c, &b, UIntPtr.Zero));
- }
-
- [Fact]
- public static void NarrowUtf16ToAscii_AllAsciiInput()
- {
- using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
- using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
-
- // Fill source with 00 .. 7F.
-
- Span<char> utf16Span = utf16Mem.Span;
- for (int i = 0; i < utf16Span.Length; i++)
- {
- utf16Span[i] = (char)i;
- }
- utf16Mem.MakeReadonly();
-
- // We'll write to the ASCII span.
- // We test with a variety of span lengths to test alignment and fallthrough code paths.
-
- Span<byte> asciiSpan = asciiMem.Span;
-
- for (int i = 0; i < utf16Span.Length; i++)
- {
- asciiSpan.Clear(); // remove any data from previous iteration
-
- // First, validate that the workhorse saw the incoming data as all-ASCII.
-
- Assert.Equal(128 - i, CallNarrowUtf16ToAscii(utf16Span.Slice(i), asciiSpan.Slice(i)));
-
- // Then, validate that the data was transcoded properly.
-
- for (int j = i; j < 128; j++)
- {
- Assert.Equal((ushort)utf16Span[i], (ushort)asciiSpan[i]);
- }
- }
- }
-
- [Fact]
- public static void NarrowUtf16ToAscii_SomeNonAsciiInput()
- {
- using BoundedMemory<char> utf16Mem = BoundedMemory.Allocate<char>(128);
- using BoundedMemory<byte> asciiMem = BoundedMemory.Allocate<byte>(128);
-
- // Fill source with 00 .. 7F.
-
- Span<char> utf16Span = utf16Mem.Span;
- for (int i = 0; i < utf16Span.Length; i++)
- {
- utf16Span[i] = (char)i;
- }
-
- // We'll write to the ASCII span.
-
- Span<byte> asciiSpan = asciiMem.Span;
-
- for (int i = utf16Span.Length - 1; i >= 0; i--)
- {
- RandomNumberGenerator.Fill(asciiSpan); // fill with garbage
-
- // First, keep track of the garbage we wrote to the destination.
- // We want to ensure it wasn't overwritten.
-
- byte[] expectedTrailingData = asciiSpan.Slice(i).ToArray();
-
- // Then, set the desired byte as non-ASCII, then check that the workhorse
- // correctly saw the data as non-ASCII.
-
- utf16Span[i] = '\u0123'; // use U+0123 instead of U+0080 since it catches inappropriate pmovmskb usage
- Assert.Equal(i, CallNarrowUtf16ToAscii(utf16Span, asciiSpan));
-
- // Next, validate that the ASCII data was transcoded properly.
-
- for (int j = 0; j < i; j++)
- {
- Assert.Equal((ushort)utf16Span[j], (ushort)asciiSpan[j]);
- }
-
- // Finally, validate that the trailing data wasn't overwritten with non-ASCII data.
-
- Assert.Equal(expectedTrailingData, asciiSpan.Slice(i).ToArray());
- }
- }
-
- private static int CallGetIndexOfFirstNonAsciiByte(ReadOnlySpan<byte> buffer)
- {
- fixed (byte* pBuffer = &MemoryMarshal.GetReference(buffer))
- {
- // Conversions between UIntPtr <-> int are not checked by default.
- return checked((int)_fnGetIndexOfFirstNonAsciiByte.Delegate(pBuffer, (UIntPtr)buffer.Length));
- }
- }
-
- private static int CallGetIndexOfFirstNonAsciiChar(ReadOnlySpan<char> buffer)
- {
- fixed (char* pBuffer = &MemoryMarshal.GetReference(buffer))
- {
- // Conversions between UIntPtr <-> int are not checked by default.
- return checked((int)_fnGetIndexOfFirstNonAsciiChar.Delegate(pBuffer, (UIntPtr)buffer.Length));
- }
- }
-
- private static int CallNarrowUtf16ToAscii(ReadOnlySpan<char> utf16, Span<byte> ascii)
- {
- Assert.Equal(utf16.Length, ascii.Length);
-
- fixed (char* pUtf16 = &MemoryMarshal.GetReference(utf16))
- fixed (byte* pAscii = &MemoryMarshal.GetReference(ascii))
- {
- // Conversions between UIntPtr <-> int are not checked by default.
- return checked((int)_fnNarrowUtf16ToAscii.Delegate(pUtf16, pAscii, (UIntPtr)utf16.Length));
- }
- }
-
- private static int CallWidenAsciiToUtf16(ReadOnlySpan<byte> ascii, Span<char> utf16)
- {
- Assert.Equal(ascii.Length, utf16.Length);
-
- fixed (byte* pAscii = &MemoryMarshal.GetReference(ascii))
- fixed (char* pUtf16 = &MemoryMarshal.GetReference(utf16))
- {
- // Conversions between UIntPtr <-> int are not checked by default.
- return checked((int)_fnWidenAsciiToUtf16.Delegate(pAscii, pUtf16, (UIntPtr)ascii.Length));
- }
- }
-
- private static Type GetAsciiUtilityType()
- {
- return typeof(object).Assembly.GetType("System.Text.ASCIIUtility");
- }
-
- private sealed class UnsafeLazyDelegate<TDelegate> where TDelegate : class
- {
- private readonly Lazy<TDelegate> _lazyDelegate;
-
- public UnsafeLazyDelegate(string methodName)
- {
- _lazyDelegate = new Lazy<TDelegate>(() =>
- {
- Assert.True(typeof(TDelegate).IsSubclassOf(typeof(MulticastDelegate)));
-
- // Get the MethodInfo for the target method
-
- MethodInfo methodInfo = GetAsciiUtilityType().GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
- Assert.NotNull(methodInfo);
-
- // Construct the TDelegate pointing to this method
-
- return (TDelegate)Activator.CreateInstance(typeof(TDelegate), new object[] { null, methodInfo.MethodHandle.GetFunctionPointer() });
- });
- }
-
- public TDelegate Delegate => _lazyDelegate.Value;
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace System.Text.Tests
+{
+ public static partial class RuneTests
+ {
+ public static IEnumerable<Rune> AllRunes()
+ {
+ for (uint i = 0; i < 0xD800; i++)
+ {
+ yield return new Rune(i);
+ }
+
+ for (uint i = 0xE000; i <= 0x10FFFF; i++)
+ {
+ yield return new Rune(i);
+ }
+ }
+
+ public static IEnumerable<object[]> GeneralTestData_BmpCodePoints_NoSurrogates()
+ {
+ yield return new object[]
+ {
+ // first BMP code point / first ASCII code point
+ new GeneralTestData
+ {
+ ScalarValue = 0x0000,
+ IsAscii = true,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\u0000' },
+ Utf8Sequence = new byte[] { 0x00 }
+ }
+ };
+
+ yield return new object[]
+ {
+ // last ASCII code point
+ new GeneralTestData
+ {
+ ScalarValue = 0x007F,
+ IsAscii = true,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\u007F' },
+ Utf8Sequence = new byte[] { 0x7F }
+ }
+ };
+
+ yield return new object[] {
+ // first non-ASCII code point / first UTF-8 two-code unit code point
+ new GeneralTestData
+ {
+ ScalarValue = 0x0080,
+ IsAscii = false,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\u0080' },
+ Utf8Sequence = new byte[] { 0xC2, 0x80 }
+ }
+ };
+
+ yield return new object[] {
+ // last UTF-8 two-code unit code point
+ new GeneralTestData
+ {
+ ScalarValue = 0x07FF,
+ IsAscii = false,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\u07FF' },
+ Utf8Sequence = new byte[] { 0xDF, 0xBF }
+ }
+ };
+
+ yield return new object[] {
+ // first UTF-8 three-code unit code point
+ new GeneralTestData
+ {
+ ScalarValue = 0x0800,
+ IsAscii = false,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\u0800' },
+ Utf8Sequence = new byte[] { 0xE0, 0xA0, 0x80 }
+ }
+ };
+
+ yield return new object[] {
+ // last code point before the surrogate range
+ new GeneralTestData
+ {
+ ScalarValue = 0xD7FF,
+ IsAscii = false,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\uD7FF' },
+ Utf8Sequence = new byte[] { 0xED, 0x9F, 0xBF }
+ }
+ };
+
+ yield return new object[] {
+ // first code point after the surrogate range
+ new GeneralTestData
+ {
+ ScalarValue = 0xE000,
+ IsAscii = false,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\uE000' },
+ Utf8Sequence = new byte[] { 0xEE, 0x80, 0x80 }
+ }
+ };
+
+ yield return new object[] {
+ // replacement character
+ new GeneralTestData
+ {
+ ScalarValue = 0xFFFD,
+ IsAscii = false,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\uFFFD' },
+ Utf8Sequence = new byte[] { 0xEF, 0xBF, 0xBD }
+ }
+ };
+
+ yield return new object[] {
+ // last BMP code point / last UTF-8 two-code unit code point
+ new GeneralTestData
+ {
+ ScalarValue = 0xFFFF,
+ IsAscii = false,
+ IsBmp = true,
+ Plane = 0,
+ Utf16Sequence = new char[] { '\uFFFF' },
+ Utf8Sequence = new byte[] { 0xEF, 0xBF, 0xBF }
+ }
+ };
+ }
+
+ public static IEnumerable<object[]> GeneralTestData_SupplementaryCodePoints_ValidOnly()
+ {
+ yield return new object[]
+ {
+ // first BMP code point / first ASCII code point
+ new GeneralTestData
+ {
+ ScalarValue = 0x10000,
+ IsAscii = false,
+ IsBmp = false,
+ Plane = 1,
+ Utf16Sequence = new char[] { '\uD800', '\uDC00' },
+ Utf8Sequence = new byte[] { 0xF0, 0x90, 0x80, 0x80 }
+ }
+ };
+
+ yield return new object[]
+ {
+ // last supplementary code point
+ new GeneralTestData
+ {
+ ScalarValue = 0x10FFFF,
+ IsAscii = false,
+ IsBmp = false,
+ Plane = 16,
+ Utf16Sequence = new char[] { '\uDBFF', '\uDFFF' },
+ Utf8Sequence = new byte[] { 0xF4, 0x8F, 0xBF, 0xBF }
+ }
+ };
+ }
+ public static IEnumerable<object[]> IsValidTestData()
+ {
+ foreach (var obj in GeneralTestData_BmpCodePoints_NoSurrogates().Concat(GeneralTestData_SupplementaryCodePoints_ValidOnly()))
+ {
+ yield return new object[] { ((GeneralTestData)obj[0]).ScalarValue /* value */, true /* isValid */ };
+ }
+
+ foreach (var obj in BmpCodePoints_SurrogatesOnly().Concat(SupplementaryCodePoints_InvalidOnly()))
+ {
+ yield return new object[] { Convert.ToInt32(obj[0], CultureInfo.InvariantCulture) /* value */, false /* isValid */ };
+ }
+ }
+
+ public static IEnumerable<object[]> BmpCodePoints_SurrogatesOnly()
+ {
+ yield return new object[] { '\uD800' }; // first high surrogate code point
+ yield return new object[] { '\uDBFF' }; // last high surrogate code point
+ yield return new object[] { '\uDC00' }; // first low surrogate code point
+ yield return new object[] { '\uDFFF' }; // last low surrogate code point
+ }
+
+ public static IEnumerable<object[]> SupplementaryCodePoints_InvalidOnly()
+ {
+ yield return new object[] { (int)-1 }; // negative code points are disallowed
+ yield return new object[] { (int)0x110000 }; // just past the end of the allowed code point range
+ yield return new object[] { int.MaxValue }; // too large
+ }
+
+ public static IEnumerable<object[]> SurrogatePairTestData_InvalidOnly()
+ {
+ yield return new object[] { '\ud800', '\ud800' }; // two high surrogates
+ yield return new object[] { '\udfff', '\udfff' }; // two low surrogates
+ yield return new object[] { '\ude00', '\udb00' }; // low surrogate before high surrogate
+ yield return new object[] { '\ud900', '\u1234' }; // high surrogate followed by non-surrogate
+ yield return new object[] { '\ud900', '\ue000' }; // high surrogate followed by value just beyond low surrogate range
+ yield return new object[] { '\u1234', '\ude00' }; // low surrogate preceded by non-surrogate
+ yield return new object[] { '\udc00', '\ude00' }; // low surrogate preceded by value just beyond high surrogate range
+ }
+
+ public static IEnumerable<object[]> SurrogatePairTestData_ValidOnly()
+ {
+ yield return new object[] { '\ud800', '\udc00', 0x00010000 }; // lower bound for high & low surrogate
+ yield return new object[] { '\udbff', '\udfff', 0x0010FFFF }; // upper bound for high & low surrogate
+ yield return new object[] { '\ud83c', '\udfa8', 0x0001F3A8 }; // U+1F3A8 ARTIST PALETTE
+ }
+
+ public class GeneralTestData
+ {
+ public int ScalarValue;
+ public bool IsAscii;
+ public bool IsBmp;
+ public int Plane;
+ public char[] Utf16Sequence;
+ public byte[] Utf8Sequence;
+ }
+
+ public static IEnumerable<object[]> UnicodeInfoTestData_Latin1AndSelectOthers()
+ {
+ // ASCII
+
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x00), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x01), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x02), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x03), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x04), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x05), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x06), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x07), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x08), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x09), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x11), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x12), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x13), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x14), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x15), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x16), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x17), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x18), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x19), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x20), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x21), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x22), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x23), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x24), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x25), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x26), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x27), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x28), UnicodeCategory = UnicodeCategory.OpenPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x29), UnicodeCategory = UnicodeCategory.ClosePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2A), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2B), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2C), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2D), UnicodeCategory = UnicodeCategory.DashPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2E), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2F), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x30), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 0, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x31), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 1, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x32), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 2, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x33), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 3, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x34), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 4, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x35), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 5, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x36), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 6, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x37), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 7, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x38), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 8, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x39), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 9, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3A), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3B), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3C), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3D), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3E), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3F), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x40), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x41), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x42), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x43), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x44), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x45), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x46), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x47), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x48), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x49), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4A), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4B), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4C), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4D), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4E), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4F), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x50), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x51), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x52), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x53), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x54), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x55), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x56), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x57), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x58), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x59), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5A), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5B), UnicodeCategory = UnicodeCategory.OpenPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5C), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5D), UnicodeCategory = UnicodeCategory.ClosePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5E), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5F), UnicodeCategory = UnicodeCategory.ConnectorPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x60), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x61), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x62), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x63), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x64), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x65), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x66), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x67), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x68), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x69), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6A), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6B), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6C), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6D), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6E), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6F), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x70), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x71), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x72), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x73), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x74), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x75), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x76), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x77), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x78), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x79), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7A), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7B), UnicodeCategory = UnicodeCategory.OpenPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7C), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7D), UnicodeCategory = UnicodeCategory.ClosePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7E), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+
+ // Remainder of Latin-1
+
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x80), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x81), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x82), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x83), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x84), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x85), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x86), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x87), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x88), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x89), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x90), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x91), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x92), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x93), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x94), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x95), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x96), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x97), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x98), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x99), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA0), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA1), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA2), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA3), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA4), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA5), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA6), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA7), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA8), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA9), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAA), UnicodeCategory = UnicodeCategory.OtherLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAB), UnicodeCategory = UnicodeCategory.InitialQuotePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAC), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAD), UnicodeCategory = UnicodeCategory.Format, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAE), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAF), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB0), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB1), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB2), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 2, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB3), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 3, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB4), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB5), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB6), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB7), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB8), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB9), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBA), UnicodeCategory = UnicodeCategory.OtherLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBB), UnicodeCategory = UnicodeCategory.FinalQuotePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBC), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 0.25, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBD), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 0.5, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBE), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 0.75, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBF), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC0), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC1), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC2), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC3), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC4), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC5), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC6), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC7), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC8), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC9), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCA), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCB), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCC), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCD), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCE), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCF), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD0), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD1), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD2), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD3), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD4), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD5), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD6), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD7), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD8), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD9), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDA), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDB), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDC), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDD), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDE), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDF), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE0), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE1), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE2), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE3), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE4), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE5), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE6), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE7), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE8), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE9), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEA), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEB), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEC), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xED), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEE), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEF), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF0), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF1), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF2), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF3), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF4), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF5), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF6), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF7), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF8), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF9), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFA), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFB), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFC), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFD), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFE), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFF), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+
+ // Select others
+
+ // U+2000 EN QUAD
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2000), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+
+ // U+2028 LINE SEPARATOR
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2028), UnicodeCategory = UnicodeCategory.LineSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+
+ // U+2029 PARAGRAPH SEPARATOR
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2029), UnicodeCategory = UnicodeCategory.ParagraphSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+
+ // U+202F NARROW NO-BREAK SPACE
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x202F), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
+
+ // U+2154 VULGAR FRACTION TWO THIRDS
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2154), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 2.0 / 3, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+
+ // U+FFFD REPLACEMENT CHARACTER
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFFFD), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
+
+ // U+10000 LINEAR B SYLLABLE B008 A
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10000), UnicodeCategory = UnicodeCategory.OtherLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+
+ // U+10110 AEGEAN NUMBER TEN
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10110), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 10, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+
+ // U+10177 GREEK TWO THIRDS SIGN
+ yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10177), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 2.0 / 3, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
+
+ }
+
+ public class UnicodeInfoTestData
+ {
+ // named such so that it appears at the beginning of the console output for any failing unit test
+ public string __DebugDisplay => $"U+{ScalarValue.Value:X4}";
+
+ public Rune ScalarValue;
+ public UnicodeCategory UnicodeCategory;
+ public double NumericValue;
+ public bool IsControl;
+ public bool IsDigit;
+ public bool IsLetter;
+ public bool IsLetterOrDigit;
+ public bool IsLower;
+ public bool IsNumber;
+ public bool IsPunctuation;
+ public bool IsSeparator;
+ public bool IsSymbol;
+ public bool IsUpper;
+ public bool IsWhiteSpace;
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-
-namespace System.Text.Tests
-{
- public static partial class RuneTests
- {
- public static IEnumerable<Rune> AllRunes()
- {
- for (uint i = 0; i < 0xD800; i++)
- {
- yield return new Rune(i);
- }
-
- for (uint i = 0xE000; i <= 0x10FFFF; i++)
- {
- yield return new Rune(i);
- }
- }
-
- public static IEnumerable<object[]> GeneralTestData_BmpCodePoints_NoSurrogates()
- {
- yield return new object[]
- {
- // first BMP code point / first ASCII code point
- new GeneralTestData
- {
- ScalarValue = 0x0000,
- IsAscii = true,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\u0000' },
- Utf8Sequence = new byte[] { 0x00 }
- }
- };
-
- yield return new object[]
- {
- // last ASCII code point
- new GeneralTestData
- {
- ScalarValue = 0x007F,
- IsAscii = true,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\u007F' },
- Utf8Sequence = new byte[] { 0x7F }
- }
- };
-
- yield return new object[] {
- // first non-ASCII code point / first UTF-8 two-code unit code point
- new GeneralTestData
- {
- ScalarValue = 0x0080,
- IsAscii = false,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\u0080' },
- Utf8Sequence = new byte[] { 0xC2, 0x80 }
- }
- };
-
- yield return new object[] {
- // last UTF-8 two-code unit code point
- new GeneralTestData
- {
- ScalarValue = 0x07FF,
- IsAscii = false,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\u07FF' },
- Utf8Sequence = new byte[] { 0xDF, 0xBF }
- }
- };
-
- yield return new object[] {
- // first UTF-8 three-code unit code point
- new GeneralTestData
- {
- ScalarValue = 0x0800,
- IsAscii = false,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\u0800' },
- Utf8Sequence = new byte[] { 0xE0, 0xA0, 0x80 }
- }
- };
-
- yield return new object[] {
- // last code point before the surrogate range
- new GeneralTestData
- {
- ScalarValue = 0xD7FF,
- IsAscii = false,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\uD7FF' },
- Utf8Sequence = new byte[] { 0xED, 0x9F, 0xBF }
- }
- };
-
- yield return new object[] {
- // first code point after the surrogate range
- new GeneralTestData
- {
- ScalarValue = 0xE000,
- IsAscii = false,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\uE000' },
- Utf8Sequence = new byte[] { 0xEE, 0x80, 0x80 }
- }
- };
-
- yield return new object[] {
- // replacement character
- new GeneralTestData
- {
- ScalarValue = 0xFFFD,
- IsAscii = false,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\uFFFD' },
- Utf8Sequence = new byte[] { 0xEF, 0xBF, 0xBD }
- }
- };
-
- yield return new object[] {
- // last BMP code point / last UTF-8 two-code unit code point
- new GeneralTestData
- {
- ScalarValue = 0xFFFF,
- IsAscii = false,
- IsBmp = true,
- Plane = 0,
- Utf16Sequence = new char[] { '\uFFFF' },
- Utf8Sequence = new byte[] { 0xEF, 0xBF, 0xBF }
- }
- };
- }
-
- public static IEnumerable<object[]> GeneralTestData_SupplementaryCodePoints_ValidOnly()
- {
- yield return new object[]
- {
- // first BMP code point / first ASCII code point
- new GeneralTestData
- {
- ScalarValue = 0x10000,
- IsAscii = false,
- IsBmp = false,
- Plane = 1,
- Utf16Sequence = new char[] { '\uD800', '\uDC00' },
- Utf8Sequence = new byte[] { 0xF0, 0x90, 0x80, 0x80 }
- }
- };
-
- yield return new object[]
- {
- // last supplementary code point
- new GeneralTestData
- {
- ScalarValue = 0x10FFFF,
- IsAscii = false,
- IsBmp = false,
- Plane = 16,
- Utf16Sequence = new char[] { '\uDBFF', '\uDFFF' },
- Utf8Sequence = new byte[] { 0xF4, 0x8F, 0xBF, 0xBF }
- }
- };
- }
- public static IEnumerable<object[]> IsValidTestData()
- {
- foreach (var obj in GeneralTestData_BmpCodePoints_NoSurrogates().Concat(GeneralTestData_SupplementaryCodePoints_ValidOnly()))
- {
- yield return new object[] { ((GeneralTestData)obj[0]).ScalarValue /* value */, true /* isValid */ };
- }
-
- foreach (var obj in BmpCodePoints_SurrogatesOnly().Concat(SupplementaryCodePoints_InvalidOnly()))
- {
- yield return new object[] { Convert.ToInt32(obj[0], CultureInfo.InvariantCulture) /* value */, false /* isValid */ };
- }
- }
-
- public static IEnumerable<object[]> BmpCodePoints_SurrogatesOnly()
- {
- yield return new object[] { '\uD800' }; // first high surrogate code point
- yield return new object[] { '\uDBFF' }; // last high surrogate code point
- yield return new object[] { '\uDC00' }; // first low surrogate code point
- yield return new object[] { '\uDFFF' }; // last low surrogate code point
- }
-
- public static IEnumerable<object[]> SupplementaryCodePoints_InvalidOnly()
- {
- yield return new object[] { (int)-1 }; // negative code points are disallowed
- yield return new object[] { (int)0x110000 }; // just past the end of the allowed code point range
- yield return new object[] { int.MaxValue }; // too large
- }
-
- public static IEnumerable<object[]> SurrogatePairTestData_InvalidOnly()
- {
- yield return new object[] { '\ud800', '\ud800' }; // two high surrogates
- yield return new object[] { '\udfff', '\udfff' }; // two low surrogates
- yield return new object[] { '\ude00', '\udb00' }; // low surrogate before high surrogate
- yield return new object[] { '\ud900', '\u1234' }; // high surrogate followed by non-surrogate
- yield return new object[] { '\ud900', '\ue000' }; // high surrogate followed by value just beyond low surrogate range
- yield return new object[] { '\u1234', '\ude00' }; // low surrogate preceded by non-surrogate
- yield return new object[] { '\udc00', '\ude00' }; // low surrogate preceded by value just beyond high surrogate range
- }
-
- public static IEnumerable<object[]> SurrogatePairTestData_ValidOnly()
- {
- yield return new object[] { '\ud800', '\udc00', 0x00010000 }; // lower bound for high & low surrogate
- yield return new object[] { '\udbff', '\udfff', 0x0010FFFF }; // upper bound for high & low surrogate
- yield return new object[] { '\ud83c', '\udfa8', 0x0001F3A8 }; // U+1F3A8 ARTIST PALETTE
- }
-
- public class GeneralTestData
- {
- public int ScalarValue;
- public bool IsAscii;
- public bool IsBmp;
- public int Plane;
- public char[] Utf16Sequence;
- public byte[] Utf8Sequence;
- }
-
- public static IEnumerable<object[]> UnicodeInfoTestData_Latin1AndSelectOthers()
- {
- // ASCII
-
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x00), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x01), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x02), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x03), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x04), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x05), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x06), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x07), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x08), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x09), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x0F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x11), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x12), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x13), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x14), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x15), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x16), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x17), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x18), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x19), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x1F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x20), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x21), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x22), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x23), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x24), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x25), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x26), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x27), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x28), UnicodeCategory = UnicodeCategory.OpenPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x29), UnicodeCategory = UnicodeCategory.ClosePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2A), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2B), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2C), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2D), UnicodeCategory = UnicodeCategory.DashPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2E), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2F), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x30), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 0, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x31), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 1, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x32), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 2, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x33), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 3, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x34), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 4, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x35), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 5, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x36), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 6, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x37), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 7, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x38), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 8, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x39), UnicodeCategory = UnicodeCategory.DecimalDigitNumber, NumericValue = 9, IsControl = false, IsDigit = true, IsLetter = false, IsLetterOrDigit = true, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3A), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3B), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3C), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3D), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3E), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x3F), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x40), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x41), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x42), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x43), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x44), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x45), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x46), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x47), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x48), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x49), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4A), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4B), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4C), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4D), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4E), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x4F), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x50), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x51), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x52), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x53), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x54), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x55), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x56), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x57), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x58), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x59), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5A), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5B), UnicodeCategory = UnicodeCategory.OpenPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5C), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5D), UnicodeCategory = UnicodeCategory.ClosePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5E), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x5F), UnicodeCategory = UnicodeCategory.ConnectorPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x60), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x61), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x62), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x63), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x64), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x65), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x66), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x67), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x68), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x69), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6A), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6B), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6C), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6D), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6E), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x6F), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x70), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x71), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x72), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x73), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x74), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x75), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x76), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x77), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x78), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x79), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7A), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7B), UnicodeCategory = UnicodeCategory.OpenPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7C), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7D), UnicodeCategory = UnicodeCategory.ClosePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7E), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x7F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
-
- // Remainder of Latin-1
-
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x80), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x81), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x82), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x83), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x84), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x85), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x86), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x87), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x88), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x89), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x8F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x90), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x91), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x92), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x93), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x94), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x95), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x96), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x97), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x98), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x99), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9A), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9B), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9C), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9D), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9E), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x9F), UnicodeCategory = UnicodeCategory.Control, NumericValue = -1, IsControl = true, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA0), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA1), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA2), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA3), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA4), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA5), UnicodeCategory = UnicodeCategory.CurrencySymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA6), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA7), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA8), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xA9), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAA), UnicodeCategory = UnicodeCategory.OtherLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAB), UnicodeCategory = UnicodeCategory.InitialQuotePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAC), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAD), UnicodeCategory = UnicodeCategory.Format, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAE), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xAF), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB0), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB1), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB2), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 2, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB3), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 3, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB4), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB5), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB6), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB7), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB8), UnicodeCategory = UnicodeCategory.ModifierSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xB9), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBA), UnicodeCategory = UnicodeCategory.OtherLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBB), UnicodeCategory = UnicodeCategory.FinalQuotePunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBC), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 0.25, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBD), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 0.5, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBE), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 0.75, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xBF), UnicodeCategory = UnicodeCategory.OtherPunctuation, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = true, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC0), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC1), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC2), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC3), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC4), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC5), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC6), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC7), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC8), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xC9), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCA), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCB), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCC), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCD), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCE), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xCF), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD0), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD1), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD2), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD3), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD4), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD5), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD6), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD7), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD8), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xD9), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDA), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDB), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDC), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDD), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDE), UnicodeCategory = UnicodeCategory.UppercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = true, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xDF), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE0), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE1), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE2), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE3), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE4), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE5), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE6), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE7), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE8), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xE9), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEA), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEB), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEC), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xED), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEE), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xEF), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF0), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF1), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF2), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF3), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF4), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF5), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF6), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF7), UnicodeCategory = UnicodeCategory.MathSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF8), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xF9), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFA), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFB), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFC), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFD), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFE), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFF), UnicodeCategory = UnicodeCategory.LowercaseLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = true, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
-
- // Select others
-
- // U+2000 EN QUAD
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2000), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
-
- // U+2028 LINE SEPARATOR
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2028), UnicodeCategory = UnicodeCategory.LineSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
-
- // U+2029 PARAGRAPH SEPARATOR
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2029), UnicodeCategory = UnicodeCategory.ParagraphSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
-
- // U+202F NARROW NO-BREAK SPACE
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x202F), UnicodeCategory = UnicodeCategory.SpaceSeparator, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = true, IsSymbol = false, IsUpper = false, IsWhiteSpace = true } };
-
- // U+2154 VULGAR FRACTION TWO THIRDS
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x2154), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 2.0 / 3, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
-
- // U+FFFD REPLACEMENT CHARACTER
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0xFFFD), UnicodeCategory = UnicodeCategory.OtherSymbol, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = true, IsUpper = false, IsWhiteSpace = false } };
-
- // U+10000 LINEAR B SYLLABLE B008 A
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10000), UnicodeCategory = UnicodeCategory.OtherLetter, NumericValue = -1, IsControl = false, IsDigit = false, IsLetter = true, IsLetterOrDigit = true, IsLower = false, IsNumber = false, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
-
- // U+10110 AEGEAN NUMBER TEN
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10110), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 10, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
-
- // U+10177 GREEK TWO THIRDS SIGN
- yield return new object[] { new UnicodeInfoTestData { ScalarValue = (Rune)(0x10177), UnicodeCategory = UnicodeCategory.OtherNumber, NumericValue = 2.0 / 3, IsControl = false, IsDigit = false, IsLetter = false, IsLetterOrDigit = false, IsLower = false, IsNumber = true, IsPunctuation = false, IsSeparator = false, IsSymbol = false, IsUpper = false, IsWhiteSpace = false } };
-
- }
-
- public class UnicodeInfoTestData
- {
- // named such so that it appears at the beginning of the console output for any failing unit test
- public string __DebugDisplay => $"U+{ScalarValue.Value:X4}";
-
- public Rune ScalarValue;
- public UnicodeCategory UnicodeCategory;
- public double NumericValue;
- public bool IsControl;
- public bool IsDigit;
- public bool IsLetter;
- public bool IsLetterOrDigit;
- public bool IsLower;
- public bool IsNumber;
- public bool IsPunctuation;
- public bool IsSeparator;
- public bool IsSymbol;
- public bool IsUpper;
- public bool IsWhiteSpace;
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Globalization;
+using System.Text.Unicode.Tests;
+using Xunit;
+using Xunit.Sdk;
+
+namespace System.Text.Tests
+{
+ public static partial class RuneTests
+ {
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [InlineData('0', '0', '0', "en-US")]
+ [InlineData('a', 'A', 'a', "en-US")]
+ [InlineData('i', 'I', 'i', "en-US")]
+ [InlineData('i', '\u0130', 'i', "tr-TR")]
+ [InlineData('z', 'Z', 'z', "en-US")]
+ [InlineData('A', 'A', 'a', "en-US")]
+ [InlineData('I', 'I', 'i', "en-US")]
+ [InlineData('I', 'I', '\u0131', "tr-TR")]
+ [InlineData('Z', 'Z', 'z', "en-US")]
+ [InlineData('\u00DF', '\u00DF', '\u00DF', "de-DE")] // U+00DF LATIN SMALL LETTER SHARP S -- n.b. ToUpper doesn't create the majuscule form
+ [InlineData('\u0130', '\u0130', 'i', "tr-TR")] // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE
+ [InlineData('\u0131', 'I', '\u0131', "tr-TR")] // U+0131 LATIN SMALL LETTER DOTLESS I
+ [InlineData('\u1E9E', '\u1E9E', '\u00DF', "de-DE")] // U+1E9E LATIN CAPITAL LETTER SHARP S
+ [InlineData(0x10400, 0x10400, 0x10428, "en-US")] // U+10400 DESERET CAPITAL LETTER LONG I
+ [InlineData(0x10428, 0x10400, 0x10428, "en-US")] // U+10428 DESERET SMALL LETTER LONG I
+ public static void Casing_CultureAware(int original, int upper, int lower, string culture)
+ {
+ var rune = new Rune(original);
+ var cultureInfo = CultureInfo.GetCultureInfo(culture);
+ Assert.Equal(new Rune(upper), Rune.ToUpper(rune, cultureInfo));
+ Assert.Equal(new Rune(lower), Rune.ToLower(rune, cultureInfo));
+ }
+
+ // Invariant ToUpper / ToLower doesn't modify Turkish I or majuscule Eszett
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [InlineData('0', '0', '0')]
+ [InlineData('a', 'A', 'a')]
+ [InlineData('i', 'I', 'i')]
+ [InlineData('z', 'Z', 'z')]
+ [InlineData('A', 'A', 'a')]
+ [InlineData('I', 'I', 'i')]
+ [InlineData('Z', 'Z', 'z')]
+ [InlineData('\u00DF', '\u00DF', '\u00DF')] // U+00DF LATIN SMALL LETTER SHARP S
+ [InlineData('\u0130', '\u0130', '\u0130')] // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE
+ [InlineData('\u0131', '\u0131', '\u0131')] // U+0131 LATIN SMALL LETTER DOTLESS I
+ [InlineData('\u1E9E', '\u1E9E', '\u1E9E')] // U+1E9E LATIN CAPITAL LETTER SHARP S
+ [InlineData(0x10400, 0x10400, 0x10428)] // U+10400 DESERET CAPITAL LETTER LONG I
+ [InlineData(0x10428, 0x10400, 0x10428)] // U+10428 DESERET SMALL LETTER LONG I
+ public static void Casing_Invariant(int original, int upper, int lower)
+ {
+ var rune = new Rune(original);
+ Assert.Equal(new Rune(upper), Rune.ToUpperInvariant(rune));
+ Assert.Equal(new Rune(lower), Rune.ToLowerInvariant(rune));
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ public static void Ctor_Cast_Char_Valid(GeneralTestData testData)
+ {
+ Rune rune = new Rune(checked((char)testData.ScalarValue));
+ Rune runeFromCast = (Rune)(char)testData.ScalarValue;
+
+ Assert.Equal(rune, runeFromCast);
+ Assert.Equal(testData.ScalarValue, rune.Value);
+ Assert.Equal(testData.IsAscii, rune.IsAscii);
+ Assert.Equal(testData.IsBmp, rune.IsBmp);
+ Assert.Equal(testData.Plane, rune.Plane);
+ }
+
+ [Theory]
+ [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
+ public static void Ctor_Cast_Char_Invalid_Throws(char ch)
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(nameof(ch), () => new Rune(ch));
+ Assert.Throws<ArgumentOutOfRangeException>(nameof(ch), () => (Rune)ch);
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
+ public static void Ctor_Cast_Int32_Valid(GeneralTestData testData)
+ {
+ Rune rune = new Rune((int)testData.ScalarValue);
+ Rune runeFromCast = (Rune)(int)testData.ScalarValue;
+
+ Assert.Equal(rune, runeFromCast);
+ Assert.Equal(testData.ScalarValue, rune.Value);
+ Assert.Equal(testData.IsAscii, rune.IsAscii);
+ Assert.Equal(testData.IsBmp, rune.IsBmp);
+ Assert.Equal(testData.Plane, rune.Plane);
+ }
+
+ [Theory]
+ [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
+ [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
+ public static void Ctor_Cast_Int32_Invalid_Throws(int value)
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => new Rune(value));
+ Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => (Rune)value);
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
+ public static void Ctor_Cast_UInt32_Valid(GeneralTestData testData)
+ {
+ Rune rune = new Rune((uint)testData.ScalarValue);
+ Rune runeFromCast = (Rune)(uint)testData.ScalarValue;
+
+ Assert.Equal(rune, runeFromCast);
+ Assert.Equal(testData.ScalarValue, rune.Value);
+ Assert.Equal(testData.IsAscii, rune.IsAscii);
+ Assert.Equal(testData.IsBmp, rune.IsBmp);
+ Assert.Equal(testData.Plane, rune.Plane);
+ }
+
+ [Theory]
+ [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
+ [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
+ public static void Ctor_Cast_UInt32_Invalid_Throws(int value)
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => new Rune((uint)value));
+ Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => (Rune)(uint)value);
+ }
+
+ [Theory]
+ [MemberData(nameof(SurrogatePairTestData_ValidOnly))]
+ public static void Ctor_SurrogatePair_Valid(char highSurrogate, char lowSurrogate, int expectedValue)
+ {
+ Assert.Equal(expectedValue, new Rune(highSurrogate, lowSurrogate).Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(SurrogatePairTestData_InvalidOnly))]
+ public static void Ctor_SurrogatePair_Valid(char highSurrogate, char lowSurrogate)
+ {
+ string expectedParamName = !char.IsHighSurrogate(highSurrogate) ? nameof(highSurrogate) : nameof(lowSurrogate);
+ Assert.Throws<ArgumentOutOfRangeException>(expectedParamName, () => new Rune(highSurrogate, lowSurrogate));
+ }
+
+ [Theory]
+ [InlineData('A', 'a', -1)]
+ [InlineData('A', 'A', 0)]
+ [InlineData('a', 'A', 1)]
+ [InlineData(0x10000, 0x10000, 0)]
+ [InlineData('\uFFFD', 0x10000, -1)]
+ [InlineData(0x10FFFF, 0x10000, 1)]
+ public static void CompareTo_And_ComparisonOperators(int first, int other, int expectedSign)
+ {
+ Rune a = new Rune(first);
+ Rune b = new Rune(other);
+
+ Assert.Equal(expectedSign, Math.Sign(a.CompareTo(b)));
+ Assert.Equal(expectedSign < 0, a < b);
+ Assert.Equal(expectedSign <= 0, a <= b);
+ Assert.Equal(expectedSign > 0, a > b);
+ Assert.Equal(expectedSign >= 0, a >= b);
+ }
+
+ [Theory]
+ [InlineData(new char[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
+ [InlineData(new char[] { '\u1234' }, OperationStatus.Done, 0x1234, 1)] // BMP char
+ [InlineData(new char[] { '\u1234', '\ud800' }, OperationStatus.Done, 0x1234, 1)] // BMP char
+ [InlineData(new char[] { '\ud83d', '\ude32' }, OperationStatus.Done, 0x1F632, 2)] // supplementary value (U+1F632 ASTONISHED FACE)
+ [InlineData(new char[] { '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
+ [InlineData(new char[] { '\udc00', '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
+ [InlineData(new char[] { '\ud800' }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // high surrogate at end of buffer
+ [InlineData(new char[] { '\ud800', '\ud800' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone high surrogate
+ [InlineData(new char[] { '\ud800', '\u1234' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone high surrogate
+ public static void DecodeFromUtf16(char[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedCharsConsumed)
+ {
+ Assert.Equal(expectedOperationStatus, Rune.DecodeFromUtf16(data, out Rune actualRune, out int actualCharsConsumed));
+ Assert.Equal(expectedRuneValue, actualRune.Value);
+ Assert.Equal(expectedCharsConsumed, actualCharsConsumed);
+ }
+
+ [Theory]
+ [InlineData(new char[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
+ [InlineData(new char[] { '\u1234', '\u5678' }, OperationStatus.Done, 0x5678, 1)] // BMP char
+ [InlineData(new char[] { '\udc00', '\ud800' }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // high surrogate at end of buffer
+ [InlineData(new char[] { '\ud83d', '\ude32' }, OperationStatus.Done, 0x1F632, 2)] // supplementary value (U+1F632 ASTONISHED FACE)
+ [InlineData(new char[] { '\u1234', '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
+ [InlineData(new char[] { '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
+ public static void DecodeLastFromUtf16(char[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedCharsConsumed)
+ {
+ Assert.Equal(expectedOperationStatus, Rune.DecodeLastFromUtf16(data, out Rune actualRune, out int actualCharsConsumed));
+ Assert.Equal(expectedRuneValue, actualRune.Value);
+ Assert.Equal(expectedCharsConsumed, actualCharsConsumed);
+ }
+
+ [Theory]
+ [InlineData(new byte[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
+ [InlineData(new byte[] { 0x30 }, OperationStatus.Done, 0x0030, 1)] // ASCII byte
+ [InlineData(new byte[] { 0x30, 0x40, 0x50 }, OperationStatus.Done, 0x0030, 1)] // ASCII byte
+ [InlineData(new byte[] { 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
+ [InlineData(new byte[] { 0x80, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
+ [InlineData(new byte[] { 0xC1 }, OperationStatus.InvalidData, 0xFFFD, 1)] // C1 is never a valid UTF-8 byte
+ [InlineData(new byte[] { 0xF5 }, OperationStatus.InvalidData, 0xFFFD, 1)] // F5 is never a valid UTF-8 byte
+ [InlineData(new byte[] { 0xC2 }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // C2 is a valid byte; expecting it to be followed by a continuation byte
+ [InlineData(new byte[] { 0xED }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // ED is a valid byte; expecting it to be followed by a continuation byte
+ [InlineData(new byte[] { 0xF4 }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // F4 is a valid byte; expecting it to be followed by a continuation byte
+ [InlineData(new byte[] { 0xC2, 0xC2 }, OperationStatus.InvalidData, 0xFFFD, 1)] // C2 not followed by continuation byte
+ [InlineData(new byte[] { 0xC3, 0x90 }, OperationStatus.Done, 0x00D0, 2)] // [ C3 90 ] is U+00D0 LATIN CAPITAL LETTER ETH
+ [InlineData(new byte[] { 0xC1, 0xBF }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ C1 BF ] is overlong 2-byte sequence, all overlong sequences have maximal invalid subsequence length 1
+ [InlineData(new byte[] { 0xE0, 0x9F }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ E0 9F ] is overlong 3-byte sequence, all overlong sequences have maximal invalid subsequence length 1
+ [InlineData(new byte[] { 0xE0, 0xA0 }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ E0 A0 ] is valid 2-byte start of 3-byte sequence
+ [InlineData(new byte[] { 0xED, 0x9F }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ ED 9F ] is valid 2-byte start of 3-byte sequence
+ [InlineData(new byte[] { 0xED, 0xBF }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ ED BF ] would place us in UTF-16 surrogate range, all surrogate sequences have maximal invalid subsequence length 1
+ [InlineData(new byte[] { 0xEE, 0x80 }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ EE 80 ] is valid 2-byte start of 3-byte sequence
+ [InlineData(new byte[] { 0xF0, 0x8F }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ F0 8F ] is overlong 4-byte sequence, all overlong sequences have maximal invalid subsequence length 1
+ [InlineData(new byte[] { 0xF0, 0x90 }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ F0 90 ] is valid 2-byte start of 4-byte sequence
+ [InlineData(new byte[] { 0xF4, 0x90 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ F4 90 ] would place us beyond U+10FFFF, all such sequences have maximal invalid subsequence length 1
+ [InlineData(new byte[] { 0xE2, 0x88, 0xB4 }, OperationStatus.Done, 0x2234, 3)] // [ E2 88 B4 ] is U+2234 THEREFORE
+ [InlineData(new byte[] { 0xE2, 0x88, 0xC0 }, OperationStatus.InvalidData, 0xFFFD, 2)] // [ E2 88 ] followed by non-continuation byte, maximal invalid subsequence length 2
+ [InlineData(new byte[] { 0xF0, 0x9F, 0x98 }, OperationStatus.NeedMoreData, 0xFFFD, 3)] // [ F0 9F 98 ] is valid 3-byte start of 4-byte sequence
+ [InlineData(new byte[] { 0xF0, 0x9F, 0x98, 0x20 }, OperationStatus.InvalidData, 0xFFFD, 3)] // [ F0 9F 98 ] followed by non-continuation byte, maximal invalid subsequence length 3
+ [InlineData(new byte[] { 0xF0, 0x9F, 0x98, 0xB2 }, OperationStatus.Done, 0x1F632, 4)] // [ F0 9F 98 B2 ] is U+1F632 ASTONISHED FACE
+ public static void DecodeFromUtf8(byte[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedBytesConsumed)
+ {
+ Assert.Equal(expectedOperationStatus, Rune.DecodeFromUtf8(data, out Rune actualRune, out int actualBytesConsumed));
+ Assert.Equal(expectedRuneValue, actualRune.Value);
+ Assert.Equal(expectedBytesConsumed, actualBytesConsumed);
+ }
+
+ [Theory]
+ [InlineData(new byte[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
+ [InlineData(new byte[] { 0x30 }, OperationStatus.Done, 0x0030, 1)] // ASCII byte
+ [InlineData(new byte[] { 0x30, 0x40, 0x50 }, OperationStatus.Done, 0x0050, 1)] // ASCII byte
+ [InlineData(new byte[] { 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
+ [InlineData(new byte[] { 0x80, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
+ [InlineData(new byte[] { 0x80, 0x80, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
+ [InlineData(new byte[] { 0x80, 0x80, 0x80, 0xC2 }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // [ C2 ] at end of buffer, valid 1-byte start of 2-byte sequence
+ [InlineData(new byte[] { 0xC1 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ C1 ] is never a valid byte
+ [InlineData(new byte[] { 0x80, 0xE2, 0x88, 0xB4 }, OperationStatus.Done, 0x2234, 3)] // [ E2 88 B4 ] is U+2234 THEREFORE
+ [InlineData(new byte[] { 0xF0, 0x9F, 0x98, 0xB2 }, OperationStatus.Done, 0x1F632, 4)] // [ F0 9F 98 B2 ] is U+1F632 ASTONISHED FACE
+ [InlineData(new byte[] { 0xE2, 0x88, 0xB4, 0xB2 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ B2 ] is standalone continuation byte
+ [InlineData(new byte[] { 0x80, 0x62, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ 80 ] is standalone continuation byte
+ [InlineData(new byte[] { 0xF0, 0x9F, 0x98, }, OperationStatus.NeedMoreData, 0xFFFD, 3)] // [ F0 9F 98 ] is valid 3-byte start of 4-byte sequence
+ public static void DecodeLastFromUtf8(byte[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedBytesConsumed)
+ {
+ Assert.Equal(expectedOperationStatus, Rune.DecodeLastFromUtf8(data, out Rune actualRune, out int actualBytesConsumed));
+ Assert.Equal(expectedRuneValue, actualRune.Value);
+ Assert.Equal(expectedBytesConsumed, actualBytesConsumed);
+ }
+
+ [Theory]
+ [InlineData(0, 0, true)]
+ [InlineData(0x10FFFF, 0x10FFFF, true)]
+ [InlineData(0xFFFD, 0xFFFD, true)]
+ [InlineData(0xFFFD, 0xFFFF, false)]
+ [InlineData('a', 'a', true)]
+ [InlineData('a', 'A', false)]
+ [InlineData('a', 'b', false)]
+ public static void Equals_OperatorEqual_OperatorNotEqual(int first, int other, bool expected)
+ {
+ Rune a = new Rune(first);
+ Rune b = new Rune(other);
+
+ Assert.Equal(expected, Object.Equals(a, b));
+ Assert.Equal(expected, a.Equals(b));
+ Assert.Equal(expected, a.Equals((object)b));
+ Assert.Equal(expected, a == b);
+ Assert.NotEqual(expected, a != b);
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData('a')]
+ [InlineData('\uFFFD')]
+ [InlineData(0x10FFFF)]
+ public static void GetHashCodeTests(int scalarValue)
+ {
+ Assert.Equal(scalarValue, new Rune(scalarValue).GetHashCode());
+ }
+
+ [Theory]
+ [InlineData("a", 0, (int)'a')]
+ [InlineData("ab", 1, (int)'b')]
+ [InlineData("x\U0001F46Ey", 3, (int)'y')]
+ [InlineData("x\U0001F46Ey", 1, 0x1F46E)] // U+1F46E POLICE OFFICER
+ public static void GetRuneAt_TryGetRuneAt_Utf16_Success(string inputString, int index, int expectedScalarValue)
+ {
+ // GetRuneAt
+ Assert.Equal(expectedScalarValue, Rune.GetRuneAt(inputString, index).Value);
+
+ // TryGetRuneAt
+ Assert.True(Rune.TryGetRuneAt(inputString, index, out Rune rune));
+ Assert.Equal(expectedScalarValue, rune.Value);
+ }
+
+ // Our unit test runner doesn't deal well with malformed literal strings, so
+ // we smuggle it as a char[] and turn it into a string within the test itself.
+ [Theory]
+ [InlineData(new char[] { 'x', '\uD83D', '\uDC6E', 'y' }, 2)] // attempt to index into the middle of a UTF-16 surrogate pair
+ [InlineData(new char[] { 'x', '\uD800', 'y' }, 1)] // high surrogate not followed by low surrogate
+ [InlineData(new char[] { 'x', '\uDFFF', '\uDFFF' }, 1)] // attempt to start at a low surrogate
+ [InlineData(new char[] { 'x', '\uD800' }, 1)] // end of string reached before could complete surrogate pair
+ public static void GetRuneAt_TryGetRuneAt_Utf16_InvalidData(char[] inputCharArray, int index)
+ {
+ string inputString = new string(inputCharArray);
+
+ // GetRuneAt
+ Assert.Throws<ArgumentException>("index", () => Rune.GetRuneAt(inputString, index));
+
+ // TryGetRuneAt
+ Assert.False(Rune.TryGetRuneAt(inputString, index, out Rune rune));
+ Assert.Equal(0, rune.Value);
+ }
+
+ [Fact]
+ public static void GetRuneAt_TryGetRuneAt_Utf16_BadArgs()
+ {
+ // null input
+ Assert.Throws<ArgumentNullException>("input", () => Rune.GetRuneAt(null, 0));
+
+ // negative index specified
+ Assert.Throws<ArgumentOutOfRangeException>("index", () => Rune.GetRuneAt("hello", -1));
+
+ // index goes past end of string
+ Assert.Throws<ArgumentOutOfRangeException>("index", () => Rune.GetRuneAt(string.Empty, 0));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void GetNumericValue(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.NumericValue, Rune.GetNumericValue(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void GetUnicodeCategory(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.UnicodeCategory, Rune.GetUnicodeCategory(testData.ScalarValue));
+ }
+
+ [OuterLoop]
+ [Fact]
+ public static void GetUnicodeCategory_AllInputs()
+ {
+ // This tests calls Rune.GetUnicodeCategory for every possible input, ensuring that
+ // the runtime agrees with the data in the core Unicode files.
+
+ foreach (Rune rune in AllRunes())
+ {
+ if (UnicodeData.GetUnicodeCategory((uint)rune.Value) != Rune.GetUnicodeCategory(rune))
+ {
+ // We'll build up the exception message ourselves so the dev knows what code point failed.
+ throw new AssertActualExpectedException(
+ expected: UnicodeData.GetUnicodeCategory((uint)rune.Value),
+ actual: Rune.GetUnicodeCategory(rune),
+ userMessage: FormattableString.Invariant($@"Rune.GetUnicodeCategory(U+{rune.Value:X4}) returned wrong value."));
+ }
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsControl(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsControl, Rune.IsControl(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsDigit(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsDigit, Rune.IsDigit(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsLetter(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsLetter, Rune.IsLetter(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsLetterOrDigit(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsLetterOrDigit, Rune.IsLetterOrDigit(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsLower(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsLower, Rune.IsLower(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsNumber(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsNumber, Rune.IsNumber(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsPunctuation(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsPunctuation, Rune.IsPunctuation(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsSeparator(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsSeparator, Rune.IsSeparator(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsSymbol(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsSymbol, Rune.IsSymbol(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsUpper(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsUpper, Rune.IsUpper(testData.ScalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(IsValidTestData))]
+ public static void IsValid(int scalarValue, bool expectedIsValid)
+ {
+ Assert.Equal(expectedIsValid, Rune.IsValid(scalarValue));
+ Assert.Equal(expectedIsValid, Rune.IsValid((uint)scalarValue));
+ }
+
+ [Theory]
+ [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
+ public static void IsWhiteSpace(UnicodeInfoTestData testData)
+ {
+ Assert.Equal(testData.IsWhiteSpace, Rune.IsWhiteSpace(testData.ScalarValue));
+ }
+
+ [OuterLoop]
+ [Fact]
+ public static void IsWhiteSpace_AllInputs()
+ {
+ // This tests calls Rune.IsWhiteSpace for every possible input, ensuring that
+ // the runtime agrees with the data in the core Unicode files.
+
+ foreach (Rune rune in AllRunes())
+ {
+ Assert.Equal(UnicodeData.IsWhiteSpace((uint)rune.Value), Rune.IsWhiteSpace(rune));
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0)]
+ [InlineData(0x80, 0x80)]
+ [InlineData(0x80, 0x100)]
+ [InlineData(0x100, 0x80)]
+ public static void Operators_And_CompareTo(uint scalarValueLeft, uint scalarValueRight)
+ {
+ Rune left = new Rune(scalarValueLeft);
+ Rune right = new Rune(scalarValueRight);
+
+ Assert.Equal(scalarValueLeft == scalarValueRight, left == right);
+ Assert.Equal(scalarValueLeft != scalarValueRight, left != right);
+ Assert.Equal(scalarValueLeft < scalarValueRight, left < right);
+ Assert.Equal(scalarValueLeft <= scalarValueRight, left <= right);
+ Assert.Equal(scalarValueLeft > scalarValueRight, left > right);
+ Assert.Equal(scalarValueLeft >= scalarValueRight, left >= right);
+ Assert.Equal(scalarValueLeft.CompareTo(scalarValueRight), left.CompareTo(right));
+ }
+
+ [Fact]
+ public static void ReplacementChar()
+ {
+ Assert.Equal(0xFFFD, Rune.ReplacementChar.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ public static void TryCreate_Char_Valid(GeneralTestData testData)
+ {
+ Assert.True(Rune.TryCreate((char)testData.ScalarValue, out Rune result));
+ Assert.Equal(testData.ScalarValue, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
+ public static void TryCreate_Char_Invalid(int scalarValue)
+ {
+ Assert.False(Rune.TryCreate((char)scalarValue, out Rune result));
+ Assert.Equal(0, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(SurrogatePairTestData_InvalidOnly))]
+ public static void TryCreate_SurrogateChars_Invalid(char highSurrogate, char lowSurrogate)
+ {
+ Assert.False(Rune.TryCreate(highSurrogate, lowSurrogate, out Rune result));
+ Assert.Equal(0, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(SurrogatePairTestData_ValidOnly))]
+ public static void TryCreate_SurrogateChars_Valid(char highSurrogate, char lowSurrogate, int expectedValue)
+ {
+ Assert.True(Rune.TryCreate(highSurrogate, lowSurrogate, out Rune result));
+ Assert.Equal(expectedValue, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
+ public static void TryCreate_Int32_Valid(GeneralTestData testData)
+ {
+ Assert.True(Rune.TryCreate((int)testData.ScalarValue, out Rune result));
+ Assert.Equal(testData.ScalarValue, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
+ [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
+ public static void TryCreate_Int32_Invalid(int scalarValue)
+ {
+ Assert.False(Rune.TryCreate((int)scalarValue, out Rune result));
+ Assert.Equal(0, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
+ public static void TryCreate_UInt32_Valid(GeneralTestData testData)
+ {
+ Assert.True(Rune.TryCreate((uint)testData.ScalarValue, out Rune result));
+ Assert.Equal(testData.ScalarValue, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
+ [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
+ public static void TryCreate_UInt32_Invalid(int scalarValue)
+ {
+ Assert.False(Rune.TryCreate((uint)scalarValue, out Rune result));
+ Assert.Equal(0, result.Value);
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
+ public static void ToStringTests(GeneralTestData testData)
+ {
+ Assert.Equal(new string(testData.Utf16Sequence), new Rune(testData.ScalarValue).ToString());
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
+ public static void TryEncodeToUtf16(GeneralTestData testData)
+ {
+ Rune rune = new Rune(testData.ScalarValue);
+ Assert.Equal(testData.Utf16Sequence.Length, rune.Utf16SequenceLength);
+
+ // First, try with a buffer that's too short
+
+ Span<char> utf16Buffer = stackalloc char[rune.Utf16SequenceLength - 1];
+ bool success = rune.TryEncodeToUtf16(utf16Buffer, out int charsWritten);
+ Assert.False(success);
+ Assert.Equal(0, charsWritten);
+
+ Assert.Throws<ArgumentException>("destination", () => rune.EncodeToUtf16(new char[rune.Utf16SequenceLength - 1]));
+
+ // Then, try with a buffer that's appropriately sized
+
+ utf16Buffer = stackalloc char[rune.Utf16SequenceLength];
+ success = rune.TryEncodeToUtf16(utf16Buffer, out charsWritten);
+ Assert.True(success);
+ Assert.Equal(testData.Utf16Sequence.Length, charsWritten);
+ Assert.True(utf16Buffer.SequenceEqual(testData.Utf16Sequence));
+
+ utf16Buffer.Clear();
+ Assert.Equal(testData.Utf16Sequence.Length, rune.EncodeToUtf16(utf16Buffer));
+ Assert.True(utf16Buffer.SequenceEqual(testData.Utf16Sequence));
+
+ // Finally, try with a buffer that's too long (should succeed)
+
+ utf16Buffer = stackalloc char[rune.Utf16SequenceLength + 1];
+ success = rune.TryEncodeToUtf16(utf16Buffer, out charsWritten);
+ Assert.True(success);
+ Assert.Equal(testData.Utf16Sequence.Length, charsWritten);
+ Assert.True(utf16Buffer.Slice(0, testData.Utf16Sequence.Length).SequenceEqual(testData.Utf16Sequence));
+
+ utf16Buffer.Clear();
+ Assert.Equal(testData.Utf16Sequence.Length, rune.EncodeToUtf16(utf16Buffer));
+ Assert.True(utf16Buffer.Slice(0, testData.Utf16Sequence.Length).SequenceEqual(testData.Utf16Sequence));
+ }
+
+ [Theory]
+ [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
+ [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
+ public static void TryEncodeToUtf8(GeneralTestData testData)
+ {
+ Rune rune = new Rune(testData.ScalarValue);
+ Assert.Equal(testData.Utf8Sequence.Length, actual: rune.Utf8SequenceLength);
+
+ // First, try with a buffer that's too short
+
+ Span<byte> utf8Buffer = stackalloc byte[rune.Utf8SequenceLength - 1];
+ bool success = rune.TryEncodeToUtf8(utf8Buffer, out int bytesWritten);
+ Assert.False(success);
+ Assert.Equal(0, bytesWritten);
+
+ Assert.Throws<ArgumentException>("destination", () => rune.EncodeToUtf8(new byte[rune.Utf8SequenceLength - 1]));
+
+ // Then, try with a buffer that's appropriately sized
+
+ utf8Buffer = stackalloc byte[rune.Utf8SequenceLength];
+ success = rune.TryEncodeToUtf8(utf8Buffer, out bytesWritten);
+ Assert.True(success);
+ Assert.Equal(testData.Utf8Sequence.Length, bytesWritten);
+ Assert.True(utf8Buffer.SequenceEqual(testData.Utf8Sequence));
+
+ utf8Buffer.Clear();
+ Assert.Equal(testData.Utf8Sequence.Length, rune.EncodeToUtf8(utf8Buffer));
+ Assert.True(utf8Buffer.SequenceEqual(testData.Utf8Sequence));
+
+ // Finally, try with a buffer that's too long (should succeed)
+
+ utf8Buffer = stackalloc byte[rune.Utf8SequenceLength + 1];
+ success = rune.TryEncodeToUtf8(utf8Buffer, out bytesWritten);
+ Assert.True(success);
+ Assert.Equal(testData.Utf8Sequence.Length, bytesWritten);
+ Assert.True(utf8Buffer.Slice(0, testData.Utf8Sequence.Length).SequenceEqual(testData.Utf8Sequence));
+
+ utf8Buffer.Clear();
+ Assert.Equal(testData.Utf8Sequence.Length, rune.EncodeToUtf8(utf8Buffer));
+ Assert.True(utf8Buffer.Slice(0, testData.Utf8Sequence.Length).SequenceEqual(testData.Utf8Sequence));
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Globalization;
-using System.Text.Unicode.Tests;
-using Xunit;
-using Xunit.Sdk;
-
-namespace System.Text.Tests
-{
- public static partial class RuneTests
- {
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+
- [PlatformSpecific(TestPlatforms.Windows)]
- [InlineData('0', '0', '0', "en-US")]
- [InlineData('a', 'A', 'a', "en-US")]
- [InlineData('i', 'I', 'i', "en-US")]
- [InlineData('i', '\u0130', 'i', "tr-TR")]
- [InlineData('z', 'Z', 'z', "en-US")]
- [InlineData('A', 'A', 'a', "en-US")]
- [InlineData('I', 'I', 'i', "en-US")]
- [InlineData('I', 'I', '\u0131', "tr-TR")]
- [InlineData('Z', 'Z', 'z', "en-US")]
- [InlineData('\u00DF', '\u00DF', '\u00DF', "de-DE")] // U+00DF LATIN SMALL LETTER SHARP S -- n.b. ToUpper doesn't create the majuscule form
- [InlineData('\u0130', '\u0130', 'i', "tr-TR")] // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE
- [InlineData('\u0131', 'I', '\u0131', "tr-TR")] // U+0131 LATIN SMALL LETTER DOTLESS I
- [InlineData('\u1E9E', '\u1E9E', '\u00DF', "de-DE")] // U+1E9E LATIN CAPITAL LETTER SHARP S
- [InlineData(0x10400, 0x10400, 0x10428, "en-US")] // U+10400 DESERET CAPITAL LETTER LONG I
- [InlineData(0x10428, 0x10400, 0x10428, "en-US")] // U+10428 DESERET SMALL LETTER LONG I
- public static void Casing_CultureAware(int original, int upper, int lower, string culture)
- {
- var rune = new Rune(original);
- var cultureInfo = CultureInfo.GetCultureInfo(culture);
- Assert.Equal(new Rune(upper), Rune.ToUpper(rune, cultureInfo));
- Assert.Equal(new Rune(lower), Rune.ToLower(rune, cultureInfo));
- }
-
- // Invariant ToUpper / ToLower doesn't modify Turkish I or majuscule Eszett
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+
- [PlatformSpecific(TestPlatforms.Windows)]
- [InlineData('0', '0', '0')]
- [InlineData('a', 'A', 'a')]
- [InlineData('i', 'I', 'i')]
- [InlineData('z', 'Z', 'z')]
- [InlineData('A', 'A', 'a')]
- [InlineData('I', 'I', 'i')]
- [InlineData('Z', 'Z', 'z')]
- [InlineData('\u00DF', '\u00DF', '\u00DF')] // U+00DF LATIN SMALL LETTER SHARP S
- [InlineData('\u0130', '\u0130', '\u0130')] // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE
- [InlineData('\u0131', '\u0131', '\u0131')] // U+0131 LATIN SMALL LETTER DOTLESS I
- [InlineData('\u1E9E', '\u1E9E', '\u1E9E')] // U+1E9E LATIN CAPITAL LETTER SHARP S
- [InlineData(0x10400, 0x10400, 0x10428)] // U+10400 DESERET CAPITAL LETTER LONG I
- [InlineData(0x10428, 0x10400, 0x10428)] // U+10428 DESERET SMALL LETTER LONG I
- public static void Casing_Invariant(int original, int upper, int lower)
- {
- var rune = new Rune(original);
- Assert.Equal(new Rune(upper), Rune.ToUpperInvariant(rune));
- Assert.Equal(new Rune(lower), Rune.ToLowerInvariant(rune));
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- public static void Ctor_Cast_Char_Valid(GeneralTestData testData)
- {
- Rune rune = new Rune(checked((char)testData.ScalarValue));
- Rune runeFromCast = (Rune)(char)testData.ScalarValue;
-
- Assert.Equal(rune, runeFromCast);
- Assert.Equal(testData.ScalarValue, rune.Value);
- Assert.Equal(testData.IsAscii, rune.IsAscii);
- Assert.Equal(testData.IsBmp, rune.IsBmp);
- Assert.Equal(testData.Plane, rune.Plane);
- }
-
- [Theory]
- [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
- public static void Ctor_Cast_Char_Invalid_Throws(char ch)
- {
- Assert.Throws<ArgumentOutOfRangeException>(nameof(ch), () => new Rune(ch));
- Assert.Throws<ArgumentOutOfRangeException>(nameof(ch), () => (Rune)ch);
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
- public static void Ctor_Cast_Int32_Valid(GeneralTestData testData)
- {
- Rune rune = new Rune((int)testData.ScalarValue);
- Rune runeFromCast = (Rune)(int)testData.ScalarValue;
-
- Assert.Equal(rune, runeFromCast);
- Assert.Equal(testData.ScalarValue, rune.Value);
- Assert.Equal(testData.IsAscii, rune.IsAscii);
- Assert.Equal(testData.IsBmp, rune.IsBmp);
- Assert.Equal(testData.Plane, rune.Plane);
- }
-
- [Theory]
- [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
- [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
- public static void Ctor_Cast_Int32_Invalid_Throws(int value)
- {
- Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => new Rune(value));
- Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => (Rune)value);
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
- public static void Ctor_Cast_UInt32_Valid(GeneralTestData testData)
- {
- Rune rune = new Rune((uint)testData.ScalarValue);
- Rune runeFromCast = (Rune)(uint)testData.ScalarValue;
-
- Assert.Equal(rune, runeFromCast);
- Assert.Equal(testData.ScalarValue, rune.Value);
- Assert.Equal(testData.IsAscii, rune.IsAscii);
- Assert.Equal(testData.IsBmp, rune.IsBmp);
- Assert.Equal(testData.Plane, rune.Plane);
- }
-
- [Theory]
- [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
- [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
- public static void Ctor_Cast_UInt32_Invalid_Throws(int value)
- {
- Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => new Rune((uint)value));
- Assert.Throws<ArgumentOutOfRangeException>(nameof(value), () => (Rune)(uint)value);
- }
-
- [Theory]
- [MemberData(nameof(SurrogatePairTestData_ValidOnly))]
- public static void Ctor_SurrogatePair_Valid(char highSurrogate, char lowSurrogate, int expectedValue)
- {
- Assert.Equal(expectedValue, new Rune(highSurrogate, lowSurrogate).Value);
- }
-
- [Theory]
- [MemberData(nameof(SurrogatePairTestData_InvalidOnly))]
- public static void Ctor_SurrogatePair_Valid(char highSurrogate, char lowSurrogate)
- {
- string expectedParamName = !char.IsHighSurrogate(highSurrogate) ? nameof(highSurrogate) : nameof(lowSurrogate);
- Assert.Throws<ArgumentOutOfRangeException>(expectedParamName, () => new Rune(highSurrogate, lowSurrogate));
- }
-
- [Theory]
- [InlineData('A', 'a', -1)]
- [InlineData('A', 'A', 0)]
- [InlineData('a', 'A', 1)]
- [InlineData(0x10000, 0x10000, 0)]
- [InlineData('\uFFFD', 0x10000, -1)]
- [InlineData(0x10FFFF, 0x10000, 1)]
- public static void CompareTo_And_ComparisonOperators(int first, int other, int expectedSign)
- {
- Rune a = new Rune(first);
- Rune b = new Rune(other);
-
- Assert.Equal(expectedSign, Math.Sign(a.CompareTo(b)));
- Assert.Equal(expectedSign < 0, a < b);
- Assert.Equal(expectedSign <= 0, a <= b);
- Assert.Equal(expectedSign > 0, a > b);
- Assert.Equal(expectedSign >= 0, a >= b);
- }
-
- [Theory]
- [InlineData(new char[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
- [InlineData(new char[] { '\u1234' }, OperationStatus.Done, 0x1234, 1)] // BMP char
- [InlineData(new char[] { '\u1234', '\ud800' }, OperationStatus.Done, 0x1234, 1)] // BMP char
- [InlineData(new char[] { '\ud83d', '\ude32' }, OperationStatus.Done, 0x1F632, 2)] // supplementary value (U+1F632 ASTONISHED FACE)
- [InlineData(new char[] { '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
- [InlineData(new char[] { '\udc00', '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
- [InlineData(new char[] { '\ud800' }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // high surrogate at end of buffer
- [InlineData(new char[] { '\ud800', '\ud800' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone high surrogate
- [InlineData(new char[] { '\ud800', '\u1234' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone high surrogate
- public static void DecodeFromUtf16(char[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedCharsConsumed)
- {
- Assert.Equal(expectedOperationStatus, Rune.DecodeFromUtf16(data, out Rune actualRune, out int actualCharsConsumed));
- Assert.Equal(expectedRuneValue, actualRune.Value);
- Assert.Equal(expectedCharsConsumed, actualCharsConsumed);
- }
-
- [Theory]
- [InlineData(new char[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
- [InlineData(new char[] { '\u1234', '\u5678' }, OperationStatus.Done, 0x5678, 1)] // BMP char
- [InlineData(new char[] { '\udc00', '\ud800' }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // high surrogate at end of buffer
- [InlineData(new char[] { '\ud83d', '\ude32' }, OperationStatus.Done, 0x1F632, 2)] // supplementary value (U+1F632 ASTONISHED FACE)
- [InlineData(new char[] { '\u1234', '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
- [InlineData(new char[] { '\udc00' }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone low surrogate
- public static void DecodeLastFromUtf16(char[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedCharsConsumed)
- {
- Assert.Equal(expectedOperationStatus, Rune.DecodeLastFromUtf16(data, out Rune actualRune, out int actualCharsConsumed));
- Assert.Equal(expectedRuneValue, actualRune.Value);
- Assert.Equal(expectedCharsConsumed, actualCharsConsumed);
- }
-
- [Theory]
- [InlineData(new byte[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
- [InlineData(new byte[] { 0x30 }, OperationStatus.Done, 0x0030, 1)] // ASCII byte
- [InlineData(new byte[] { 0x30, 0x40, 0x50 }, OperationStatus.Done, 0x0030, 1)] // ASCII byte
- [InlineData(new byte[] { 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
- [InlineData(new byte[] { 0x80, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
- [InlineData(new byte[] { 0xC1 }, OperationStatus.InvalidData, 0xFFFD, 1)] // C1 is never a valid UTF-8 byte
- [InlineData(new byte[] { 0xF5 }, OperationStatus.InvalidData, 0xFFFD, 1)] // F5 is never a valid UTF-8 byte
- [InlineData(new byte[] { 0xC2 }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // C2 is a valid byte; expecting it to be followed by a continuation byte
- [InlineData(new byte[] { 0xED }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // ED is a valid byte; expecting it to be followed by a continuation byte
- [InlineData(new byte[] { 0xF4 }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // F4 is a valid byte; expecting it to be followed by a continuation byte
- [InlineData(new byte[] { 0xC2, 0xC2 }, OperationStatus.InvalidData, 0xFFFD, 1)] // C2 not followed by continuation byte
- [InlineData(new byte[] { 0xC3, 0x90 }, OperationStatus.Done, 0x00D0, 2)] // [ C3 90 ] is U+00D0 LATIN CAPITAL LETTER ETH
- [InlineData(new byte[] { 0xC1, 0xBF }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ C1 BF ] is overlong 2-byte sequence, all overlong sequences have maximal invalid subsequence length 1
- [InlineData(new byte[] { 0xE0, 0x9F }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ E0 9F ] is overlong 3-byte sequence, all overlong sequences have maximal invalid subsequence length 1
- [InlineData(new byte[] { 0xE0, 0xA0 }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ E0 A0 ] is valid 2-byte start of 3-byte sequence
- [InlineData(new byte[] { 0xED, 0x9F }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ ED 9F ] is valid 2-byte start of 3-byte sequence
- [InlineData(new byte[] { 0xED, 0xBF }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ ED BF ] would place us in UTF-16 surrogate range, all surrogate sequences have maximal invalid subsequence length 1
- [InlineData(new byte[] { 0xEE, 0x80 }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ EE 80 ] is valid 2-byte start of 3-byte sequence
- [InlineData(new byte[] { 0xF0, 0x8F }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ F0 8F ] is overlong 4-byte sequence, all overlong sequences have maximal invalid subsequence length 1
- [InlineData(new byte[] { 0xF0, 0x90 }, OperationStatus.NeedMoreData, 0xFFFD, 2)] // [ F0 90 ] is valid 2-byte start of 4-byte sequence
- [InlineData(new byte[] { 0xF4, 0x90 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ F4 90 ] would place us beyond U+10FFFF, all such sequences have maximal invalid subsequence length 1
- [InlineData(new byte[] { 0xE2, 0x88, 0xB4 }, OperationStatus.Done, 0x2234, 3)] // [ E2 88 B4 ] is U+2234 THEREFORE
- [InlineData(new byte[] { 0xE2, 0x88, 0xC0 }, OperationStatus.InvalidData, 0xFFFD, 2)] // [ E2 88 ] followed by non-continuation byte, maximal invalid subsequence length 2
- [InlineData(new byte[] { 0xF0, 0x9F, 0x98 }, OperationStatus.NeedMoreData, 0xFFFD, 3)] // [ F0 9F 98 ] is valid 3-byte start of 4-byte sequence
- [InlineData(new byte[] { 0xF0, 0x9F, 0x98, 0x20 }, OperationStatus.InvalidData, 0xFFFD, 3)] // [ F0 9F 98 ] followed by non-continuation byte, maximal invalid subsequence length 3
- [InlineData(new byte[] { 0xF0, 0x9F, 0x98, 0xB2 }, OperationStatus.Done, 0x1F632, 4)] // [ F0 9F 98 B2 ] is U+1F632 ASTONISHED FACE
- public static void DecodeFromUtf8(byte[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedBytesConsumed)
- {
- Assert.Equal(expectedOperationStatus, Rune.DecodeFromUtf8(data, out Rune actualRune, out int actualBytesConsumed));
- Assert.Equal(expectedRuneValue, actualRune.Value);
- Assert.Equal(expectedBytesConsumed, actualBytesConsumed);
- }
-
- [Theory]
- [InlineData(new byte[0], OperationStatus.NeedMoreData, 0xFFFD, 0)] // empty buffer
- [InlineData(new byte[] { 0x30 }, OperationStatus.Done, 0x0030, 1)] // ASCII byte
- [InlineData(new byte[] { 0x30, 0x40, 0x50 }, OperationStatus.Done, 0x0050, 1)] // ASCII byte
- [InlineData(new byte[] { 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
- [InlineData(new byte[] { 0x80, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
- [InlineData(new byte[] { 0x80, 0x80, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // standalone continuation byte
- [InlineData(new byte[] { 0x80, 0x80, 0x80, 0xC2 }, OperationStatus.NeedMoreData, 0xFFFD, 1)] // [ C2 ] at end of buffer, valid 1-byte start of 2-byte sequence
- [InlineData(new byte[] { 0xC1 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ C1 ] is never a valid byte
- [InlineData(new byte[] { 0x80, 0xE2, 0x88, 0xB4 }, OperationStatus.Done, 0x2234, 3)] // [ E2 88 B4 ] is U+2234 THEREFORE
- [InlineData(new byte[] { 0xF0, 0x9F, 0x98, 0xB2 }, OperationStatus.Done, 0x1F632, 4)] // [ F0 9F 98 B2 ] is U+1F632 ASTONISHED FACE
- [InlineData(new byte[] { 0xE2, 0x88, 0xB4, 0xB2 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ B2 ] is standalone continuation byte
- [InlineData(new byte[] { 0x80, 0x62, 0x80, 0x80 }, OperationStatus.InvalidData, 0xFFFD, 1)] // [ 80 ] is standalone continuation byte
- [InlineData(new byte[] { 0xF0, 0x9F, 0x98, }, OperationStatus.NeedMoreData, 0xFFFD, 3)] // [ F0 9F 98 ] is valid 3-byte start of 4-byte sequence
- public static void DecodeLastFromUtf8(byte[] data, OperationStatus expectedOperationStatus, int expectedRuneValue, int expectedBytesConsumed)
- {
- Assert.Equal(expectedOperationStatus, Rune.DecodeLastFromUtf8(data, out Rune actualRune, out int actualBytesConsumed));
- Assert.Equal(expectedRuneValue, actualRune.Value);
- Assert.Equal(expectedBytesConsumed, actualBytesConsumed);
- }
-
- [Theory]
- [InlineData(0, 0, true)]
- [InlineData(0x10FFFF, 0x10FFFF, true)]
- [InlineData(0xFFFD, 0xFFFD, true)]
- [InlineData(0xFFFD, 0xFFFF, false)]
- [InlineData('a', 'a', true)]
- [InlineData('a', 'A', false)]
- [InlineData('a', 'b', false)]
- public static void Equals_OperatorEqual_OperatorNotEqual(int first, int other, bool expected)
- {
- Rune a = new Rune(first);
- Rune b = new Rune(other);
-
- Assert.Equal(expected, Object.Equals(a, b));
- Assert.Equal(expected, a.Equals(b));
- Assert.Equal(expected, a.Equals((object)b));
- Assert.Equal(expected, a == b);
- Assert.NotEqual(expected, a != b);
- }
-
- [Theory]
- [InlineData(0)]
- [InlineData('a')]
- [InlineData('\uFFFD')]
- [InlineData(0x10FFFF)]
- public static void GetHashCodeTests(int scalarValue)
- {
- Assert.Equal(scalarValue, new Rune(scalarValue).GetHashCode());
- }
-
- [Theory]
- [InlineData("a", 0, (int)'a')]
- [InlineData("ab", 1, (int)'b')]
- [InlineData("x\U0001F46Ey", 3, (int)'y')]
- [InlineData("x\U0001F46Ey", 1, 0x1F46E)] // U+1F46E POLICE OFFICER
- public static void GetRuneAt_TryGetRuneAt_Utf16_Success(string inputString, int index, int expectedScalarValue)
- {
- // GetRuneAt
- Assert.Equal(expectedScalarValue, Rune.GetRuneAt(inputString, index).Value);
-
- // TryGetRuneAt
- Assert.True(Rune.TryGetRuneAt(inputString, index, out Rune rune));
- Assert.Equal(expectedScalarValue, rune.Value);
- }
-
- // Our unit test runner doesn't deal well with malformed literal strings, so
- // we smuggle it as a char[] and turn it into a string within the test itself.
- [Theory]
- [InlineData(new char[] { 'x', '\uD83D', '\uDC6E', 'y' }, 2)] // attempt to index into the middle of a UTF-16 surrogate pair
- [InlineData(new char[] { 'x', '\uD800', 'y' }, 1)] // high surrogate not followed by low surrogate
- [InlineData(new char[] { 'x', '\uDFFF', '\uDFFF' }, 1)] // attempt to start at a low surrogate
- [InlineData(new char[] { 'x', '\uD800' }, 1)] // end of string reached before could complete surrogate pair
- public static void GetRuneAt_TryGetRuneAt_Utf16_InvalidData(char[] inputCharArray, int index)
- {
- string inputString = new string(inputCharArray);
-
- // GetRuneAt
- Assert.Throws<ArgumentException>("index", () => Rune.GetRuneAt(inputString, index));
-
- // TryGetRuneAt
- Assert.False(Rune.TryGetRuneAt(inputString, index, out Rune rune));
- Assert.Equal(0, rune.Value);
- }
-
- [Fact]
- public static void GetRuneAt_TryGetRuneAt_Utf16_BadArgs()
- {
- // null input
- Assert.Throws<ArgumentNullException>("input", () => Rune.GetRuneAt(null, 0));
-
- // negative index specified
- Assert.Throws<ArgumentOutOfRangeException>("index", () => Rune.GetRuneAt("hello", -1));
-
- // index goes past end of string
- Assert.Throws<ArgumentOutOfRangeException>("index", () => Rune.GetRuneAt(string.Empty, 0));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void GetNumericValue(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.NumericValue, Rune.GetNumericValue(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void GetUnicodeCategory(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.UnicodeCategory, Rune.GetUnicodeCategory(testData.ScalarValue));
- }
-
- [OuterLoop]
- [Fact]
- public static void GetUnicodeCategory_AllInputs()
- {
- // This tests calls Rune.GetUnicodeCategory for every possible input, ensuring that
- // the runtime agrees with the data in the core Unicode files.
-
- foreach (Rune rune in AllRunes())
- {
- if (UnicodeData.GetUnicodeCategory((uint)rune.Value) != Rune.GetUnicodeCategory(rune))
- {
- // We'll build up the exception message ourselves so the dev knows what code point failed.
- throw new AssertActualExpectedException(
- expected: UnicodeData.GetUnicodeCategory((uint)rune.Value),
- actual: Rune.GetUnicodeCategory(rune),
- userMessage: FormattableString.Invariant($@"Rune.GetUnicodeCategory(U+{rune.Value:X4}) returned wrong value."));
- }
- }
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsControl(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsControl, Rune.IsControl(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsDigit(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsDigit, Rune.IsDigit(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsLetter(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsLetter, Rune.IsLetter(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsLetterOrDigit(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsLetterOrDigit, Rune.IsLetterOrDigit(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsLower(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsLower, Rune.IsLower(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsNumber(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsNumber, Rune.IsNumber(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsPunctuation(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsPunctuation, Rune.IsPunctuation(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsSeparator(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsSeparator, Rune.IsSeparator(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsSymbol(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsSymbol, Rune.IsSymbol(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsUpper(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsUpper, Rune.IsUpper(testData.ScalarValue));
- }
-
- [Theory]
- [MemberData(nameof(IsValidTestData))]
- public static void IsValid(int scalarValue, bool expectedIsValid)
- {
- Assert.Equal(expectedIsValid, Rune.IsValid(scalarValue));
- Assert.Equal(expectedIsValid, Rune.IsValid((uint)scalarValue));
- }
-
- [Theory]
- [MemberData(nameof(UnicodeInfoTestData_Latin1AndSelectOthers))]
- public static void IsWhiteSpace(UnicodeInfoTestData testData)
- {
- Assert.Equal(testData.IsWhiteSpace, Rune.IsWhiteSpace(testData.ScalarValue));
- }
-
- [OuterLoop]
- [Fact]
- public static void IsWhiteSpace_AllInputs()
- {
- // This tests calls Rune.IsWhiteSpace for every possible input, ensuring that
- // the runtime agrees with the data in the core Unicode files.
-
- foreach (Rune rune in AllRunes())
- {
- Assert.Equal(UnicodeData.IsWhiteSpace((uint)rune.Value), Rune.IsWhiteSpace(rune));
- }
- }
-
- [Theory]
- [InlineData(0, 0)]
- [InlineData(0x80, 0x80)]
- [InlineData(0x80, 0x100)]
- [InlineData(0x100, 0x80)]
- public static void Operators_And_CompareTo(uint scalarValueLeft, uint scalarValueRight)
- {
- Rune left = new Rune(scalarValueLeft);
- Rune right = new Rune(scalarValueRight);
-
- Assert.Equal(scalarValueLeft == scalarValueRight, left == right);
- Assert.Equal(scalarValueLeft != scalarValueRight, left != right);
- Assert.Equal(scalarValueLeft < scalarValueRight, left < right);
- Assert.Equal(scalarValueLeft <= scalarValueRight, left <= right);
- Assert.Equal(scalarValueLeft > scalarValueRight, left > right);
- Assert.Equal(scalarValueLeft >= scalarValueRight, left >= right);
- Assert.Equal(scalarValueLeft.CompareTo(scalarValueRight), left.CompareTo(right));
- }
-
- [Fact]
- public static void ReplacementChar()
- {
- Assert.Equal(0xFFFD, Rune.ReplacementChar.Value);
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- public static void TryCreate_Char_Valid(GeneralTestData testData)
- {
- Assert.True(Rune.TryCreate((char)testData.ScalarValue, out Rune result));
- Assert.Equal(testData.ScalarValue, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
- public static void TryCreate_Char_Invalid(int scalarValue)
- {
- Assert.False(Rune.TryCreate((char)scalarValue, out Rune result));
- Assert.Equal(0, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(SurrogatePairTestData_InvalidOnly))]
- public static void TryCreate_SurrogateChars_Invalid(char highSurrogate, char lowSurrogate)
- {
- Assert.False(Rune.TryCreate(highSurrogate, lowSurrogate, out Rune result));
- Assert.Equal(0, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(SurrogatePairTestData_ValidOnly))]
- public static void TryCreate_SurrogateChars_Valid(char highSurrogate, char lowSurrogate, int expectedValue)
- {
- Assert.True(Rune.TryCreate(highSurrogate, lowSurrogate, out Rune result));
- Assert.Equal(expectedValue, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
- public static void TryCreate_Int32_Valid(GeneralTestData testData)
- {
- Assert.True(Rune.TryCreate((int)testData.ScalarValue, out Rune result));
- Assert.Equal(testData.ScalarValue, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
- [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
- public static void TryCreate_Int32_Invalid(int scalarValue)
- {
- Assert.False(Rune.TryCreate((int)scalarValue, out Rune result));
- Assert.Equal(0, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
- public static void TryCreate_UInt32_Valid(GeneralTestData testData)
- {
- Assert.True(Rune.TryCreate((uint)testData.ScalarValue, out Rune result));
- Assert.Equal(testData.ScalarValue, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(BmpCodePoints_SurrogatesOnly))]
- [MemberData(nameof(SupplementaryCodePoints_InvalidOnly))]
- public static void TryCreate_UInt32_Invalid(int scalarValue)
- {
- Assert.False(Rune.TryCreate((uint)scalarValue, out Rune result));
- Assert.Equal(0, result.Value);
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
- public static void ToStringTests(GeneralTestData testData)
- {
- Assert.Equal(new string(testData.Utf16Sequence), new Rune(testData.ScalarValue).ToString());
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
- public static void TryEncodeToUtf16(GeneralTestData testData)
- {
- Rune rune = new Rune(testData.ScalarValue);
- Assert.Equal(testData.Utf16Sequence.Length, rune.Utf16SequenceLength);
-
- // First, try with a buffer that's too short
-
- Span<char> utf16Buffer = stackalloc char[rune.Utf16SequenceLength - 1];
- bool success = rune.TryEncodeToUtf16(utf16Buffer, out int charsWritten);
- Assert.False(success);
- Assert.Equal(0, charsWritten);
-
- Assert.Throws<ArgumentException>("destination", () => rune.EncodeToUtf16(new char[rune.Utf16SequenceLength - 1]));
-
- // Then, try with a buffer that's appropriately sized
-
- utf16Buffer = stackalloc char[rune.Utf16SequenceLength];
- success = rune.TryEncodeToUtf16(utf16Buffer, out charsWritten);
- Assert.True(success);
- Assert.Equal(testData.Utf16Sequence.Length, charsWritten);
- Assert.True(utf16Buffer.SequenceEqual(testData.Utf16Sequence));
-
- utf16Buffer.Clear();
- Assert.Equal(testData.Utf16Sequence.Length, rune.EncodeToUtf16(utf16Buffer));
- Assert.True(utf16Buffer.SequenceEqual(testData.Utf16Sequence));
-
- // Finally, try with a buffer that's too long (should succeed)
-
- utf16Buffer = stackalloc char[rune.Utf16SequenceLength + 1];
- success = rune.TryEncodeToUtf16(utf16Buffer, out charsWritten);
- Assert.True(success);
- Assert.Equal(testData.Utf16Sequence.Length, charsWritten);
- Assert.True(utf16Buffer.Slice(0, testData.Utf16Sequence.Length).SequenceEqual(testData.Utf16Sequence));
-
- utf16Buffer.Clear();
- Assert.Equal(testData.Utf16Sequence.Length, rune.EncodeToUtf16(utf16Buffer));
- Assert.True(utf16Buffer.Slice(0, testData.Utf16Sequence.Length).SequenceEqual(testData.Utf16Sequence));
- }
-
- [Theory]
- [MemberData(nameof(GeneralTestData_BmpCodePoints_NoSurrogates))]
- [MemberData(nameof(GeneralTestData_SupplementaryCodePoints_ValidOnly))]
- public static void TryEncodeToUtf8(GeneralTestData testData)
- {
- Rune rune = new Rune(testData.ScalarValue);
- Assert.Equal(testData.Utf8Sequence.Length, actual: rune.Utf8SequenceLength);
-
- // First, try with a buffer that's too short
-
- Span<byte> utf8Buffer = stackalloc byte[rune.Utf8SequenceLength - 1];
- bool success = rune.TryEncodeToUtf8(utf8Buffer, out int bytesWritten);
- Assert.False(success);
- Assert.Equal(0, bytesWritten);
-
- Assert.Throws<ArgumentException>("destination", () => rune.EncodeToUtf8(new byte[rune.Utf8SequenceLength - 1]));
-
- // Then, try with a buffer that's appropriately sized
-
- utf8Buffer = stackalloc byte[rune.Utf8SequenceLength];
- success = rune.TryEncodeToUtf8(utf8Buffer, out bytesWritten);
- Assert.True(success);
- Assert.Equal(testData.Utf8Sequence.Length, bytesWritten);
- Assert.True(utf8Buffer.SequenceEqual(testData.Utf8Sequence));
-
- utf8Buffer.Clear();
- Assert.Equal(testData.Utf8Sequence.Length, rune.EncodeToUtf8(utf8Buffer));
- Assert.True(utf8Buffer.SequenceEqual(testData.Utf8Sequence));
-
- // Finally, try with a buffer that's too long (should succeed)
-
- utf8Buffer = stackalloc byte[rune.Utf8SequenceLength + 1];
- success = rune.TryEncodeToUtf8(utf8Buffer, out bytesWritten);
- Assert.True(success);
- Assert.Equal(testData.Utf8Sequence.Length, bytesWritten);
- Assert.True(utf8Buffer.Slice(0, testData.Utf8Sequence.Length).SequenceEqual(testData.Utf8Sequence));
-
- utf8Buffer.Clear();
- Assert.Equal(testData.Utf8Sequence.Length, rune.EncodeToUtf8(utf8Buffer));
- Assert.True(utf8Buffer.Slice(0, testData.Utf8Sequence.Length).SequenceEqual(testData.Utf8Sequence));
- }
- }
-}
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
+using System.Linq;
using System.Tests;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
public string Format(string format, object arg, IFormatProvider formatProvider) => "abc";
public object GetFormat(Type formatType) => this;
}
+
+ [Fact]
+ public static void AppendJoin_NullValues_ThrowsArgumentNullException()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin('|', (object[])null));
+ AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin('|', (IEnumerable<object>)null));
+ AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin('|', (string[])null));
+ AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin("|", (object[])null));
+ AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin("|", (IEnumerable<object>)null));
+ AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin("|", (string[])null));
+ }
+
+ [Theory]
+ [InlineData(new object[0], "")]
+ [InlineData(new object[] { null }, "")]
+ [InlineData(new object[] { 10 }, "10")]
+ [InlineData(new object[] { null, null }, "|")]
+ [InlineData(new object[] { null, 20 }, "|20")]
+ [InlineData(new object[] { 10, null }, "10|")]
+ [InlineData(new object[] { 10, 20 }, "10|20")]
+ [InlineData(new object[] { null, null, null }, "||")]
+ [InlineData(new object[] { null, null, 30 }, "||30")]
+ [InlineData(new object[] { null, 20, null }, "|20|")]
+ [InlineData(new object[] { null, 20, 30 }, "|20|30")]
+ [InlineData(new object[] { 10, null, null }, "10||")]
+ [InlineData(new object[] { 10, null, 30 }, "10||30")]
+ [InlineData(new object[] { 10, 20, null }, "10|20|")]
+ [InlineData(new object[] { 10, 20, 30 }, "10|20|30")]
+ [InlineData(new object[] { "" }, "")]
+ [InlineData(new object[] { "", "" }, "|")]
+ public static void AppendJoin_TestValues(object[] values, string expected)
+ {
+ var stringValues = Array.ConvertAll(values, _ => _?.ToString());
+ var enumerable = values.Select(_ => _);
+
+ Assert.Equal(expected, new StringBuilder().AppendJoin('|', values).ToString());
+ Assert.Equal(expected, new StringBuilder().AppendJoin('|', enumerable).ToString());
+ Assert.Equal(expected, new StringBuilder().AppendJoin('|', stringValues).ToString());
+ Assert.Equal(expected, new StringBuilder().AppendJoin("|", values).ToString());
+ Assert.Equal(expected, new StringBuilder().AppendJoin("|", enumerable).ToString());
+ Assert.Equal(expected, new StringBuilder().AppendJoin("|", stringValues).ToString());
+ }
+
+ [Fact]
+ public static void AppendJoin_NullToStringValues()
+ {
+ AppendJoin_TestValues(new object[] { new NullToStringObject() }, "");
+ AppendJoin_TestValues(new object[] { new NullToStringObject(), new NullToStringObject() }, "|");
+ }
+
+ private sealed class NullToStringObject
+ {
+ public override string ToString() => null;
+ }
+
+ [Theory]
+ [InlineData(null, "123")]
+ [InlineData("", "123")]
+ [InlineData(" ", "1 2 3")]
+ [InlineData(", ", "1, 2, 3")]
+ public static void AppendJoin_TestStringSeparators(string separator, string expected)
+ {
+ Assert.Equal(expected, new StringBuilder().AppendJoin(separator, new object[] { 1, 2, 3 }).ToString());
+ Assert.Equal(expected, new StringBuilder().AppendJoin(separator, Enumerable.Range(1, 3)).ToString());
+ Assert.Equal(expected, new StringBuilder().AppendJoin(separator, new string[] { "1", "2", "3" }).ToString());
+ }
+
+
+ private static StringBuilder CreateBuilderWithNoSpareCapacity()
+ {
+ return new StringBuilder(0, 5).Append("Hello");
+ }
+
+ [Theory]
+ [InlineData(null, new object[] { null, null })]
+ [InlineData("", new object[] { "", "" })]
+ [InlineData(" ", new object[] { })]
+ [InlineData(", ", new object[] { "" })]
+ public static void AppendJoin_NoValues_NoSpareCapacity_DoesNotThrow(string separator, object[] values)
+ {
+ var stringValues = Array.ConvertAll(values, _ => _?.ToString());
+ var enumerable = values.Select(_ => _);
+
+ if (separator?.Length == 1)
+ {
+ CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values);
+ CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable);
+ CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues);
+ }
+ CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values);
+ CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable);
+ CreateBuilderWithNoSpareCapacity().AppendJoin(separator, stringValues);
+ }
+
+ [Theory]
+ [InlineData(null, new object[] { " " })]
+ [InlineData(" ", new object[] { " " })]
+ [InlineData(" ", new object[] { null, null })]
+ [InlineData(" ", new object[] { "", "" })]
+ public static void AppendJoin_NoSpareCapacity_ThrowsArgumentOutOfRangeException(string separator, object[] values)
+ {
+ var builder = new StringBuilder(0, 5);
+ builder.Append("Hello");
+
+ var stringValues = Array.ConvertAll(values, _ => _?.ToString());
+ var enumerable = values.Select(_ => _);
+
+ if (separator?.Length == 1)
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues));
+ }
+ AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, stringValues));
+ }
+
+ [Theory]
+ [InlineData("Hello", new char[] { 'a' }, "Helloa")]
+ [InlineData("Hello", new char[] { 'b', 'c', 'd' }, "Hellobcd")]
+ [InlineData("Hello", new char[] { 'b', '\0', 'd' }, "Hellob\0d")]
+ [InlineData("", new char[] { 'e', 'f', 'g' }, "efg")]
+ [InlineData("Hello", new char[0], "Hello")]
+ public static void Append_CharSpan(string original, char[] value, string expected)
+ {
+ var builder = new StringBuilder(original);
+ builder.Append(new ReadOnlySpan<char>(value));
+ Assert.Equal(expected, builder.ToString());
+ }
+
+ [Theory]
+ [InlineData("Hello", new char[] { 'a' }, "Helloa")]
+ [InlineData("Hello", new char[] { 'b', 'c', 'd' }, "Hellobcd")]
+ [InlineData("Hello", new char[] { 'b', '\0', 'd' }, "Hellob\0d")]
+ [InlineData("", new char[] { 'e', 'f', 'g' }, "efg")]
+ [InlineData("Hello", new char[0], "Hello")]
+ public static void Append_CharMemory(string original, char[] value, string expected)
+ {
+ var builder = new StringBuilder(original);
+ builder.Append(value.AsMemory());
+ Assert.Equal(expected, builder.ToString());
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(10000)]
+ public static void Clear_AppendAndInsertBeforeClearManyTimes_CapacityStaysWithinRange(int times)
+ {
+ var builder = new StringBuilder();
+ var originalCapacity = builder.Capacity;
+ var s = new string(' ', 10);
+ int oldLength = 0;
+ for (int i = 0; i < times; i++)
+ {
+ builder.Append(s);
+ builder.Append(s);
+ builder.Append(s);
+ builder.Insert(0, s);
+ builder.Insert(0, s);
+ oldLength = builder.Length;
+
+ builder.Clear();
+ }
+ Assert.InRange(builder.Capacity, 1, oldLength * 1.2);
+ }
+
+ [Fact]
+ public static void Clear_InitialCapacityMuchLargerThanLength_CapacityReducedToInitialCapacity()
+ {
+ var builder = new StringBuilder(100);
+ var initialCapacity = builder.Capacity;
+ builder.Append(new string('a', 40));
+ builder.Insert(0, new string('a', 10));
+ builder.Insert(0, new string('a', 10));
+ builder.Insert(0, new string('a', 10));
+ var oldCapacity = builder.Capacity;
+ var oldLength = builder.Length;
+ builder.Clear();
+ Assert.NotEqual(oldCapacity, builder.Capacity);
+ Assert.Equal(initialCapacity, builder.Capacity);
+ Assert.NotInRange(builder.Capacity, 1, oldLength * 1.2);
+ Assert.InRange(builder.Capacity, 1, Math.Max(initialCapacity, oldLength * 1.2));
+ }
+
+ [Fact]
+ public static void Clear_StringBuilderHasTwoChunks_OneChunkIsEmpty_ClearReducesCapacity()
+ {
+ var sb = new StringBuilder(string.Empty);
+ int initialCapacity = sb.Capacity;
+ for (int i = 0; i < initialCapacity; i++)
+ {
+ sb.Append('a');
+ }
+ sb.Insert(0, 'a');
+ while (sb.Length > 1)
+ {
+ sb.Remove(1, 1);
+ }
+ int oldCapacity = sb.Capacity;
+ sb.Clear();
+ Assert.Equal(oldCapacity - 1, sb.Capacity);
+ Assert.Equal(initialCapacity, sb.Capacity);
+ }
+
+ [Theory]
+ [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0' }, 5, new char[] { 'H', 'e', 'l', 'l', 'o' })]
+ [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0' }, 4, new char[] { 'H', 'e', 'l', 'l' })]
+ [InlineData("Hello", 1, new char[] { '\0', '\0', '\0', '\0', '\0' }, 4, new char[] { 'e', 'l', 'l', 'o', '\0' })]
+ public static void CopyTo_CharSpan(string value, int sourceIndex, char[] destination, int count, char[] expected)
+ {
+ var builder = new StringBuilder(value);
+ builder.CopyTo(sourceIndex, new Span<char>(destination), count);
+ Assert.Equal(expected, destination);
+ }
+
+ [Fact]
+ public static void CopyTo_CharSpan_StringBuilderWithMultipleChunks()
+ {
+ StringBuilder builder = StringBuilderWithMultipleChunks();
+ char[] destination = new char[builder.Length];
+ builder.CopyTo(0, new Span<char>(destination), destination.Length);
+ Assert.Equal(s_chunkSplitSource.ToCharArray(), destination);
+ }
+
+ [Fact]
+ public static void CopyTo_CharSpan_Invalid()
+ {
+ var builder = new StringBuilder("Hello");
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("sourceIndex", () => builder.CopyTo(-1, new Span<char>(new char[10]), 0)); // Source index < 0
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("sourceIndex", () => builder.CopyTo(6, new Span<char>(new char[10]), 0)); // Source index > builder.Length
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => builder.CopyTo(0, new Span<char>(new char[10]), -1)); // Count < 0
+
+ AssertExtensions.Throws<ArgumentException>(null, () => builder.CopyTo(5, new Span<char>(new char[10]), 1)); // Source index + count > builder.Length
+ AssertExtensions.Throws<ArgumentException>(null, () => builder.CopyTo(4, new Span<char>(new char[10]), 2)); // Source index + count > builder.Length
+
+ AssertExtensions.Throws<ArgumentException>(null, () => builder.CopyTo(0, new Span<char>(new char[10]), 11)); // count > destinationArray.Length
+ }
+
+ [Theory]
+ [InlineData("Hello", 0, new char[] { '\0' }, "\0Hello")]
+ [InlineData("Hello", 3, new char[] { 'a', 'b', 'c' }, "Helabclo")]
+ [InlineData("Hello", 5, new char[] { 'd', 'e', 'f' }, "Hellodef")]
+ [InlineData("Hello", 0, new char[0], "Hello")]
+ public static void Insert_CharSpan(string original, int index, char[] value, string expected)
+ {
+ var builder = new StringBuilder(original);
+ builder.Insert(index, new ReadOnlySpan<char>(value));
+ Assert.Equal(expected, builder.ToString());
+ }
+
+ [Fact]
+ public static void Insert_CharSpan_Invalid()
+ {
+ var builder = new StringBuilder(0, 5);
+ builder.Append("Hello");
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => builder.Insert(-1, new ReadOnlySpan<char>(new char[0]))); // Index < 0
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => builder.Insert(builder.Length + 1, new ReadOnlySpan<char>(new char[0]))); // Index > builder.Length
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("requiredLength", () => builder.Insert(builder.Length, new ReadOnlySpan<char>(new char[1]))); // New length > builder.MaxCapacity
+ }
+
+ public static IEnumerable<object[]> Append_StringBuilder_TestData()
+ {
+ string mediumString = new string('a', 30);
+ string largeString = new string('b', 1000);
+
+ var sb1 = new StringBuilder("Hello");
+ var sb2 = new StringBuilder("one");
+ var sb3 = new StringBuilder(20).Append(mediumString);
+
+ yield return new object[] { new StringBuilder("Hello"), sb1, "HelloHello" };
+ yield return new object[] { new StringBuilder("Hello"), sb2, "Helloone" };
+ yield return new object[] { new StringBuilder("Hello"), new StringBuilder(), "Hello" };
+
+ yield return new object[] { new StringBuilder("one"), sb3, "one" + mediumString };
+
+ yield return new object[] { new StringBuilder(20).Append(mediumString), sb3, mediumString + mediumString };
+ yield return new object[] { new StringBuilder(10).Append(mediumString), sb3, mediumString + mediumString };
+
+ yield return new object[] { new StringBuilder(20).Append(largeString), sb3, largeString + mediumString };
+ yield return new object[] { new StringBuilder(10).Append(largeString), sb3, largeString + mediumString };
+
+ yield return new object[] { new StringBuilder(10), sb3, mediumString };
+ yield return new object[] { new StringBuilder(30), sb3, mediumString };
+ yield return new object[] { new StringBuilder(10), new StringBuilder(20), string.Empty};
+
+ yield return new object[] { sb1, null, "Hello" };
+ yield return new object[] { sb1, sb1, "HelloHello" };
+ }
+
+ [Theory]
+ [MemberData(nameof(Append_StringBuilder_TestData))]
+ public static void Append_StringBuilder(StringBuilder s1, StringBuilder s2, string s)
+ {
+ Assert.Equal(s, s1.Append(s2).ToString());
+ }
+
+ public static IEnumerable<object[]> Append_StringBuilder_Substring_TestData()
+ {
+ string mediumString = new string('a', 30);
+ string largeString = new string('b', 1000);
+
+ var sb1 = new StringBuilder("Hello");
+ var sb2 = new StringBuilder("one");
+ var sb3 = new StringBuilder(20).Append(mediumString);
+
+ yield return new object[] { new StringBuilder("Hello"), sb1, 0, 5, "HelloHello" };
+ yield return new object[] { new StringBuilder("Hello"), sb1, 0, 0, "Hello" };
+ yield return new object[] { new StringBuilder("Hello"), sb1, 2, 3, "Hellollo" };
+ yield return new object[] { new StringBuilder("Hello"), sb1, 2, 2, "Helloll" };
+ yield return new object[] { new StringBuilder("Hello"), sb1, 2, 0, "Hello" };
+ yield return new object[] { new StringBuilder("Hello"), new StringBuilder(), 0, 0, "Hello" };
+ yield return new object[] { new StringBuilder("Hello"), null, 0, 0, "Hello" };
+ yield return new object[] { new StringBuilder(), new StringBuilder("Hello"), 2, 3, "llo" };
+ yield return new object[] { new StringBuilder("Hello"), sb2, 0, 3, "Helloone" };
+
+ yield return new object[] { new StringBuilder("one"), sb3, 5, 25, "one" + new string('a', 25) };
+ yield return new object[] { new StringBuilder("one"), sb3, 5, 20, "one" + new string('a', 20) };
+ yield return new object[] { new StringBuilder("one"), sb3, 10, 10, "one" + new string('a', 10) };
+
+ yield return new object[] { new StringBuilder(20).Append(mediumString), sb3, 20, 10, new string('a', 40) };
+ yield return new object[] { new StringBuilder(10).Append(mediumString), sb3, 10, 10, new string('a', 40) };
+
+ yield return new object[] { new StringBuilder(20).Append(largeString), new StringBuilder(20).Append(largeString), 100, 50, largeString + new string('b', 50) };
+ yield return new object[] { new StringBuilder(10).Append(mediumString), new StringBuilder(20).Append(largeString), 20, 10, mediumString + new string('b', 10) };
+ yield return new object[] { new StringBuilder(10).Append(mediumString), new StringBuilder(20).Append(largeString), 100, 50, mediumString + new string('b', 50) };
+
+ yield return new object[] { sb1, sb1, 2, 3, "Hellollo" };
+ yield return new object[] { sb2, sb2, 2, 0, "one" };
+ }
+
+ [Theory]
+ [MemberData(nameof(Append_StringBuilder_Substring_TestData))]
+ public static void Append_StringBuilder_Substring(StringBuilder s1, StringBuilder s2, int startIndex, int count, string s)
+ {
+ Assert.Equal(s, s1.Append(s2, startIndex, count).ToString());
+ }
+
+ [Fact]
+ public static void Append_StringBuilder_InvalidInput()
+ {
+ StringBuilder sb = new StringBuilder(5, 5).Append("Hello");
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb, -1, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb, 0, -1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb, 4, 5));
+
+ Assert.Throws<ArgumentNullException>(() => sb.Append( (StringBuilder)null, 2, 2));
+ Assert.Throws<ArgumentNullException>(() => sb.Append((StringBuilder)null, 2, 3));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new StringBuilder(3, 6).Append("Hello").Append(sb));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new StringBuilder(3, 6).Append("Hello").Append("Hello"));
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb));
+ }
+
+ public static IEnumerable<object[]> Equals_String_TestData()
+ {
+ string mediumString = new string('a', 30);
+ string largeString = new string('a', 1000);
+ string extraLargeString = new string('a', 41000); // 8000 is the maximum chunk size
+
+ var sb1 = new StringBuilder("Hello");
+ var sb2 = new StringBuilder(20).Append(mediumString);
+ var sb3 = new StringBuilder(20).Append(largeString);
+ var sb4 = new StringBuilder(20).Append(extraLargeString);
+
+ yield return new object[] { sb1, "Hello", true };
+ yield return new object[] { sb1, "Hel", false };
+ yield return new object[] { sb1, "Hellz", false };
+ yield return new object[] { sb1, "Helloz", false };
+ yield return new object[] { sb1, "", false };
+ yield return new object[] { new StringBuilder(), "", true };
+ yield return new object[] { new StringBuilder(), "Hello", false };
+ yield return new object[] { sb2, mediumString, true };
+ yield return new object[] { sb2, "H", false };
+ yield return new object[] { sb3, largeString, true };
+ yield return new object[] { sb3, "H", false };
+ yield return new object[] { sb3, new string('a', 999) + 'b', false };
+ yield return new object[] { sb4, extraLargeString, true };
+ yield return new object[] { sb4, "H", false };
+ }
+
+ [Theory]
+ [MemberData(nameof(Equals_String_TestData))]
+ public static void Equals(StringBuilder sb1, string value, bool expected)
+ {
+ Assert.Equal(expected, sb1.Equals(value.AsSpan()));
+ }
+
+ [Fact]
+ public static void ForEach()
+ {
+ // Test on a variety of lengths, at least up to the point of 9 8K chunks = 72K because this is where
+ // we start using a different technique for creating the ChunkEnumerator. 200 * 500 = 100K which hits this.
+ for (int i = 0; i < 200; i++)
+ {
+ StringBuilder inBuilder = new StringBuilder();
+ for (int j = 0; j < i; j++)
+ {
+ // Make some unique strings that are at least 500 bytes long.
+ inBuilder.Append(j);
+ inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz01_");
+ inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz0123_");
+ inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz012345_");
+ inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz012345678_");
+ inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz01234567890_");
+ }
+
+ // Copy the string out (not using StringBuilder).
+ string outStr = "";
+ foreach (ReadOnlyMemory<char> chunk in inBuilder.GetChunks())
+ outStr += new string(chunk.Span);
+
+ // The strings formed by concatenating the chunks should be the same as the value in the StringBuilder.
+ Assert.Equal(outStr, inBuilder.ToString());
+ }
+ }
+
+ [Fact]
+ public static void EqualsIgnoresCapacity()
+ {
+ var sb1 = new StringBuilder(5);
+ var sb2 = new StringBuilder(10);
+
+ Assert.True(sb1.Equals(sb2));
+
+ sb1.Append("12345");
+ sb2.Append("12345");
+
+ Assert.True(sb1.Equals(sb2));
+ }
+
+ [Fact]
+ public static void EqualsIgnoresMaxCapacity()
+ {
+ var sb1 = new StringBuilder(5, 5);
+ var sb2 = new StringBuilder(5, 10);
+
+ Assert.True(sb1.Equals(sb2));
+
+ sb1.Append("12345");
+ sb2.Append("12345");
+
+ Assert.True(sb1.Equals(sb2));
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using Xunit;
-
-namespace System.Text.Tests
-{
- public partial class StringBuilderTests
- {
- [Fact]
- public static void AppendJoin_NullValues_ThrowsArgumentNullException()
- {
- AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin('|', (object[])null));
- AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin('|', (IEnumerable<object>)null));
- AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin('|', (string[])null));
- AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin("|", (object[])null));
- AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin("|", (IEnumerable<object>)null));
- AssertExtensions.Throws<ArgumentNullException>("values", () => new StringBuilder().AppendJoin("|", (string[])null));
- }
-
- [Theory]
- [InlineData(new object[0], "")]
- [InlineData(new object[] { null }, "")]
- [InlineData(new object[] { 10 }, "10")]
- [InlineData(new object[] { null, null }, "|")]
- [InlineData(new object[] { null, 20 }, "|20")]
- [InlineData(new object[] { 10, null }, "10|")]
- [InlineData(new object[] { 10, 20 }, "10|20")]
- [InlineData(new object[] { null, null, null }, "||")]
- [InlineData(new object[] { null, null, 30 }, "||30")]
- [InlineData(new object[] { null, 20, null }, "|20|")]
- [InlineData(new object[] { null, 20, 30 }, "|20|30")]
- [InlineData(new object[] { 10, null, null }, "10||")]
- [InlineData(new object[] { 10, null, 30 }, "10||30")]
- [InlineData(new object[] { 10, 20, null }, "10|20|")]
- [InlineData(new object[] { 10, 20, 30 }, "10|20|30")]
- [InlineData(new object[] { "" }, "")]
- [InlineData(new object[] { "", "" }, "|")]
- public static void AppendJoin_TestValues(object[] values, string expected)
- {
- var stringValues = Array.ConvertAll(values, _ => _?.ToString());
- var enumerable = values.Select(_ => _);
-
- Assert.Equal(expected, new StringBuilder().AppendJoin('|', values).ToString());
- Assert.Equal(expected, new StringBuilder().AppendJoin('|', enumerable).ToString());
- Assert.Equal(expected, new StringBuilder().AppendJoin('|', stringValues).ToString());
- Assert.Equal(expected, new StringBuilder().AppendJoin("|", values).ToString());
- Assert.Equal(expected, new StringBuilder().AppendJoin("|", enumerable).ToString());
- Assert.Equal(expected, new StringBuilder().AppendJoin("|", stringValues).ToString());
- }
-
- [Fact]
- public static void AppendJoin_NullToStringValues()
- {
- AppendJoin_TestValues(new object[] { new NullToStringObject() }, "");
- AppendJoin_TestValues(new object[] { new NullToStringObject(), new NullToStringObject() }, "|");
- }
-
- private sealed class NullToStringObject
- {
- public override string ToString() => null;
- }
-
- [Theory]
- [InlineData(null, "123")]
- [InlineData("", "123")]
- [InlineData(" ", "1 2 3")]
- [InlineData(", ", "1, 2, 3")]
- public static void AppendJoin_TestStringSeparators(string separator, string expected)
- {
- Assert.Equal(expected, new StringBuilder().AppendJoin(separator, new object[] { 1, 2, 3 }).ToString());
- Assert.Equal(expected, new StringBuilder().AppendJoin(separator, Enumerable.Range(1, 3)).ToString());
- Assert.Equal(expected, new StringBuilder().AppendJoin(separator, new string[] { "1", "2", "3" }).ToString());
- }
-
-
- private static StringBuilder CreateBuilderWithNoSpareCapacity()
- {
- return new StringBuilder(0, 5).Append("Hello");
- }
-
- [Theory]
- [InlineData(null, new object[] { null, null })]
- [InlineData("", new object[] { "", "" })]
- [InlineData(" ", new object[] { })]
- [InlineData(", ", new object[] { "" })]
- public static void AppendJoin_NoValues_NoSpareCapacity_DoesNotThrow(string separator, object[] values)
- {
- var stringValues = Array.ConvertAll(values, _ => _?.ToString());
- var enumerable = values.Select(_ => _);
-
- if (separator?.Length == 1)
- {
- CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values);
- CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable);
- CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues);
- }
- CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values);
- CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable);
- CreateBuilderWithNoSpareCapacity().AppendJoin(separator, stringValues);
- }
-
- [Theory]
- [InlineData(null, new object[] { " " })]
- [InlineData(" ", new object[] { " " })]
- [InlineData(" ", new object[] { null, null })]
- [InlineData(" ", new object[] { "", "" })]
- public static void AppendJoin_NoSpareCapacity_ThrowsArgumentOutOfRangeException(string separator, object[] values)
- {
- var builder = new StringBuilder(0, 5);
- builder.Append("Hello");
-
- var stringValues = Array.ConvertAll(values, _ => _?.ToString());
- var enumerable = values.Select(_ => _);
-
- if (separator?.Length == 1)
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values));
- AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable));
- AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues));
- }
- AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values));
- AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable));
- AssertExtensions.Throws<ArgumentOutOfRangeException>(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, stringValues));
- }
-
- [Theory]
- [InlineData("Hello", new char[] { 'a' }, "Helloa")]
- [InlineData("Hello", new char[] { 'b', 'c', 'd' }, "Hellobcd")]
- [InlineData("Hello", new char[] { 'b', '\0', 'd' }, "Hellob\0d")]
- [InlineData("", new char[] { 'e', 'f', 'g' }, "efg")]
- [InlineData("Hello", new char[0], "Hello")]
- public static void Append_CharSpan(string original, char[] value, string expected)
- {
- var builder = new StringBuilder(original);
- builder.Append(new ReadOnlySpan<char>(value));
- Assert.Equal(expected, builder.ToString());
- }
-
- [Theory]
- [InlineData("Hello", new char[] { 'a' }, "Helloa")]
- [InlineData("Hello", new char[] { 'b', 'c', 'd' }, "Hellobcd")]
- [InlineData("Hello", new char[] { 'b', '\0', 'd' }, "Hellob\0d")]
- [InlineData("", new char[] { 'e', 'f', 'g' }, "efg")]
- [InlineData("Hello", new char[0], "Hello")]
- public static void Append_CharMemory(string original, char[] value, string expected)
- {
- var builder = new StringBuilder(original);
- builder.Append(value.AsMemory());
- Assert.Equal(expected, builder.ToString());
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(10000)]
- public static void Clear_AppendAndInsertBeforeClearManyTimes_CapacityStaysWithinRange(int times)
- {
- var builder = new StringBuilder();
- var originalCapacity = builder.Capacity;
- var s = new string(' ', 10);
- int oldLength = 0;
- for (int i = 0; i < times; i++)
- {
- builder.Append(s);
- builder.Append(s);
- builder.Append(s);
- builder.Insert(0, s);
- builder.Insert(0, s);
- oldLength = builder.Length;
-
- builder.Clear();
- }
- Assert.InRange(builder.Capacity, 1, oldLength * 1.2);
- }
-
- [Fact]
- public static void Clear_InitialCapacityMuchLargerThanLength_CapacityReducedToInitialCapacity()
- {
- var builder = new StringBuilder(100);
- var initialCapacity = builder.Capacity;
- builder.Append(new string('a', 40));
- builder.Insert(0, new string('a', 10));
- builder.Insert(0, new string('a', 10));
- builder.Insert(0, new string('a', 10));
- var oldCapacity = builder.Capacity;
- var oldLength = builder.Length;
- builder.Clear();
- Assert.NotEqual(oldCapacity, builder.Capacity);
- Assert.Equal(initialCapacity, builder.Capacity);
- Assert.NotInRange(builder.Capacity, 1, oldLength * 1.2);
- Assert.InRange(builder.Capacity, 1, Math.Max(initialCapacity, oldLength * 1.2));
- }
-
- [Fact]
- public static void Clear_StringBuilderHasTwoChunks_OneChunkIsEmpty_ClearReducesCapacity()
- {
- var sb = new StringBuilder(string.Empty);
- int initialCapacity = sb.Capacity;
- for (int i = 0; i < initialCapacity; i++)
- {
- sb.Append('a');
- }
- sb.Insert(0, 'a');
- while (sb.Length > 1)
- {
- sb.Remove(1, 1);
- }
- int oldCapacity = sb.Capacity;
- sb.Clear();
- Assert.Equal(oldCapacity - 1, sb.Capacity);
- Assert.Equal(initialCapacity, sb.Capacity);
- }
-
- [Theory]
- [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0' }, 5, new char[] { 'H', 'e', 'l', 'l', 'o' })]
- [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0' }, 4, new char[] { 'H', 'e', 'l', 'l' })]
- [InlineData("Hello", 1, new char[] { '\0', '\0', '\0', '\0', '\0' }, 4, new char[] { 'e', 'l', 'l', 'o', '\0' })]
- public static void CopyTo_CharSpan(string value, int sourceIndex, char[] destination, int count, char[] expected)
- {
- var builder = new StringBuilder(value);
- builder.CopyTo(sourceIndex, new Span<char>(destination), count);
- Assert.Equal(expected, destination);
- }
-
- [Fact]
- public static void CopyTo_CharSpan_StringBuilderWithMultipleChunks()
- {
- StringBuilder builder = StringBuilderWithMultipleChunks();
- char[] destination = new char[builder.Length];
- builder.CopyTo(0, new Span<char>(destination), destination.Length);
- Assert.Equal(s_chunkSplitSource.ToCharArray(), destination);
- }
-
- [Fact]
- public static void CopyTo_CharSpan_Invalid()
- {
- var builder = new StringBuilder("Hello");
-
- AssertExtensions.Throws<ArgumentOutOfRangeException>("sourceIndex", () => builder.CopyTo(-1, new Span<char>(new char[10]), 0)); // Source index < 0
- AssertExtensions.Throws<ArgumentOutOfRangeException>("sourceIndex", () => builder.CopyTo(6, new Span<char>(new char[10]), 0)); // Source index > builder.Length
-
- AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => builder.CopyTo(0, new Span<char>(new char[10]), -1)); // Count < 0
-
- AssertExtensions.Throws<ArgumentException>(null, () => builder.CopyTo(5, new Span<char>(new char[10]), 1)); // Source index + count > builder.Length
- AssertExtensions.Throws<ArgumentException>(null, () => builder.CopyTo(4, new Span<char>(new char[10]), 2)); // Source index + count > builder.Length
-
- AssertExtensions.Throws<ArgumentException>(null, () => builder.CopyTo(0, new Span<char>(new char[10]), 11)); // count > destinationArray.Length
- }
-
- [Theory]
- [InlineData("Hello", 0, new char[] { '\0' }, "\0Hello")]
- [InlineData("Hello", 3, new char[] { 'a', 'b', 'c' }, "Helabclo")]
- [InlineData("Hello", 5, new char[] { 'd', 'e', 'f' }, "Hellodef")]
- [InlineData("Hello", 0, new char[0], "Hello")]
- public static void Insert_CharSpan(string original, int index, char[] value, string expected)
- {
- var builder = new StringBuilder(original);
- builder.Insert(index, new ReadOnlySpan<char>(value));
- Assert.Equal(expected, builder.ToString());
- }
-
- [Fact]
- public static void Insert_CharSpan_Invalid()
- {
- var builder = new StringBuilder(0, 5);
- builder.Append("Hello");
-
- AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => builder.Insert(-1, new ReadOnlySpan<char>(new char[0]))); // Index < 0
- AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => builder.Insert(builder.Length + 1, new ReadOnlySpan<char>(new char[0]))); // Index > builder.Length
- AssertExtensions.Throws<ArgumentOutOfRangeException>("requiredLength", () => builder.Insert(builder.Length, new ReadOnlySpan<char>(new char[1]))); // New length > builder.MaxCapacity
- }
-
- public static IEnumerable<object[]> Append_StringBuilder_TestData()
- {
- string mediumString = new string('a', 30);
- string largeString = new string('b', 1000);
-
- var sb1 = new StringBuilder("Hello");
- var sb2 = new StringBuilder("one");
- var sb3 = new StringBuilder(20).Append(mediumString);
-
- yield return new object[] { new StringBuilder("Hello"), sb1, "HelloHello" };
- yield return new object[] { new StringBuilder("Hello"), sb2, "Helloone" };
- yield return new object[] { new StringBuilder("Hello"), new StringBuilder(), "Hello" };
-
- yield return new object[] { new StringBuilder("one"), sb3, "one" + mediumString };
-
- yield return new object[] { new StringBuilder(20).Append(mediumString), sb3, mediumString + mediumString };
- yield return new object[] { new StringBuilder(10).Append(mediumString), sb3, mediumString + mediumString };
-
- yield return new object[] { new StringBuilder(20).Append(largeString), sb3, largeString + mediumString };
- yield return new object[] { new StringBuilder(10).Append(largeString), sb3, largeString + mediumString };
-
- yield return new object[] { new StringBuilder(10), sb3, mediumString };
- yield return new object[] { new StringBuilder(30), sb3, mediumString };
- yield return new object[] { new StringBuilder(10), new StringBuilder(20), string.Empty};
-
- yield return new object[] { sb1, null, "Hello" };
- yield return new object[] { sb1, sb1, "HelloHello" };
- }
-
- [Theory]
- [MemberData(nameof(Append_StringBuilder_TestData))]
- public static void Append_StringBuilder(StringBuilder s1, StringBuilder s2, string s)
- {
- Assert.Equal(s, s1.Append(s2).ToString());
- }
-
- public static IEnumerable<object[]> Append_StringBuilder_Substring_TestData()
- {
- string mediumString = new string('a', 30);
- string largeString = new string('b', 1000);
-
- var sb1 = new StringBuilder("Hello");
- var sb2 = new StringBuilder("one");
- var sb3 = new StringBuilder(20).Append(mediumString);
-
- yield return new object[] { new StringBuilder("Hello"), sb1, 0, 5, "HelloHello" };
- yield return new object[] { new StringBuilder("Hello"), sb1, 0, 0, "Hello" };
- yield return new object[] { new StringBuilder("Hello"), sb1, 2, 3, "Hellollo" };
- yield return new object[] { new StringBuilder("Hello"), sb1, 2, 2, "Helloll" };
- yield return new object[] { new StringBuilder("Hello"), sb1, 2, 0, "Hello" };
- yield return new object[] { new StringBuilder("Hello"), new StringBuilder(), 0, 0, "Hello" };
- yield return new object[] { new StringBuilder("Hello"), null, 0, 0, "Hello" };
- yield return new object[] { new StringBuilder(), new StringBuilder("Hello"), 2, 3, "llo" };
- yield return new object[] { new StringBuilder("Hello"), sb2, 0, 3, "Helloone" };
-
- yield return new object[] { new StringBuilder("one"), sb3, 5, 25, "one" + new string('a', 25) };
- yield return new object[] { new StringBuilder("one"), sb3, 5, 20, "one" + new string('a', 20) };
- yield return new object[] { new StringBuilder("one"), sb3, 10, 10, "one" + new string('a', 10) };
-
- yield return new object[] { new StringBuilder(20).Append(mediumString), sb3, 20, 10, new string('a', 40) };
- yield return new object[] { new StringBuilder(10).Append(mediumString), sb3, 10, 10, new string('a', 40) };
-
- yield return new object[] { new StringBuilder(20).Append(largeString), new StringBuilder(20).Append(largeString), 100, 50, largeString + new string('b', 50) };
- yield return new object[] { new StringBuilder(10).Append(mediumString), new StringBuilder(20).Append(largeString), 20, 10, mediumString + new string('b', 10) };
- yield return new object[] { new StringBuilder(10).Append(mediumString), new StringBuilder(20).Append(largeString), 100, 50, mediumString + new string('b', 50) };
-
- yield return new object[] { sb1, sb1, 2, 3, "Hellollo" };
- yield return new object[] { sb2, sb2, 2, 0, "one" };
- }
-
- [Theory]
- [MemberData(nameof(Append_StringBuilder_Substring_TestData))]
- public static void Append_StringBuilder_Substring(StringBuilder s1, StringBuilder s2, int startIndex, int count, string s)
- {
- Assert.Equal(s, s1.Append(s2, startIndex, count).ToString());
- }
-
- [Fact]
- public static void Append_StringBuilder_InvalidInput()
- {
- StringBuilder sb = new StringBuilder(5, 5).Append("Hello");
-
- Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb, -1, 0));
- Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb, 0, -1));
- Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb, 4, 5));
-
- Assert.Throws<ArgumentNullException>(() => sb.Append( (StringBuilder)null, 2, 2));
- Assert.Throws<ArgumentNullException>(() => sb.Append((StringBuilder)null, 2, 3));
- Assert.Throws<ArgumentOutOfRangeException>(() => new StringBuilder(3, 6).Append("Hello").Append(sb));
- Assert.Throws<ArgumentOutOfRangeException>(() => new StringBuilder(3, 6).Append("Hello").Append("Hello"));
-
- Assert.Throws<ArgumentOutOfRangeException>(() => sb.Append(sb));
- }
-
- public static IEnumerable<object[]> Equals_String_TestData()
- {
- string mediumString = new string('a', 30);
- string largeString = new string('a', 1000);
- string extraLargeString = new string('a', 41000); // 8000 is the maximum chunk size
-
- var sb1 = new StringBuilder("Hello");
- var sb2 = new StringBuilder(20).Append(mediumString);
- var sb3 = new StringBuilder(20).Append(largeString);
- var sb4 = new StringBuilder(20).Append(extraLargeString);
-
- yield return new object[] { sb1, "Hello", true };
- yield return new object[] { sb1, "Hel", false };
- yield return new object[] { sb1, "Hellz", false };
- yield return new object[] { sb1, "Helloz", false };
- yield return new object[] { sb1, "", false };
- yield return new object[] { new StringBuilder(), "", true };
- yield return new object[] { new StringBuilder(), "Hello", false };
- yield return new object[] { sb2, mediumString, true };
- yield return new object[] { sb2, "H", false };
- yield return new object[] { sb3, largeString, true };
- yield return new object[] { sb3, "H", false };
- yield return new object[] { sb3, new string('a', 999) + 'b', false };
- yield return new object[] { sb4, extraLargeString, true };
- yield return new object[] { sb4, "H", false };
- }
-
- [Theory]
- [MemberData(nameof(Equals_String_TestData))]
- public static void Equals(StringBuilder sb1, string value, bool expected)
- {
- Assert.Equal(expected, sb1.Equals(value.AsSpan()));
- }
-
- [Fact]
- public static void ForEach()
- {
- // Test on a variety of lengths, at least up to the point of 9 8K chunks = 72K because this is where
- // we start using a different technique for creating the ChunkEnumerator. 200 * 500 = 100K which hits this.
- for (int i = 0; i < 200; i++)
- {
- StringBuilder inBuilder = new StringBuilder();
- for (int j = 0; j < i; j++)
- {
- // Make some unique strings that are at least 500 bytes long.
- inBuilder.Append(j);
- inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz01_");
- inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz0123_");
- inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz012345_");
- inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz012345678_");
- inBuilder.Append("_abcdefghijklmnopqrstuvwxyz01234567890__Abcdefghijklmnopqrstuvwxyz01234567890__ABcdefghijklmnopqrstuvwxyz01234567890_");
- }
-
- // Copy the string out (not using StringBuilder).
- string outStr = "";
- foreach (ReadOnlyMemory<char> chunk in inBuilder.GetChunks())
- outStr += new string(chunk.Span);
-
- // The strings formed by concatenating the chunks should be the same as the value in the StringBuilder.
- Assert.Equal(outStr, inBuilder.ToString());
- }
- }
-
- [Fact]
- public static void EqualsIgnoresCapacity()
- {
- var sb1 = new StringBuilder(5);
- var sb2 = new StringBuilder(10);
-
- Assert.True(sb1.Equals(sb2));
-
- sb1.Append("12345");
- sb2.Append("12345");
-
- Assert.True(sb1.Equals(sb2));
- }
-
- [Fact]
- public static void EqualsIgnoresMaxCapacity()
- {
- var sb1 = new StringBuilder(5, 5);
- var sb2 = new StringBuilder(5, 10);
-
- Assert.True(sb1.Equals(sb2));
-
- sb1.Append("12345");
- sb2.Append("12345");
-
- Assert.True(sb1.Equals(sb2));
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text.RegularExpressions;
+using Xunit;
+using Xunit.Sdk;
+
+namespace System.Text.Unicode.Tests
+{
+ /*
+ * This file contains helpers for parsing the Unicode data files, which we can then use to test
+ * our Framework's implementations of various character & text processing routines.
+ */
+
+ public static class UnicodeData
+ {
+ private const string UnicodeDataFilename = "UnicodeData.11.0.txt";
+ private const string CaseFoldingFilename = "CaseFolding-12.1.0.txt";
+ private const string PropListFilename = "PropList-12.1.0.txt";
+
+ private static readonly Dictionary<string, UnicodeCategory> _categoryCodeMap = new Dictionary<string, UnicodeCategory>()
+ {
+ { "Lu", UnicodeCategory.UppercaseLetter },
+ { "Ll", UnicodeCategory.LowercaseLetter },
+ { "Lt", UnicodeCategory.TitlecaseLetter },
+ { "Lm", UnicodeCategory.ModifierLetter },
+ { "Lo", UnicodeCategory.OtherLetter },
+ { "Mn", UnicodeCategory.NonSpacingMark },
+ { "Mc", UnicodeCategory.SpacingCombiningMark },
+ { "Me", UnicodeCategory.EnclosingMark },
+ { "Nd", UnicodeCategory.DecimalDigitNumber },
+ { "Nl", UnicodeCategory.LetterNumber },
+ { "No", UnicodeCategory.OtherNumber },
+ { "Pc", UnicodeCategory.ConnectorPunctuation },
+ { "Pd", UnicodeCategory.DashPunctuation },
+ { "Ps", UnicodeCategory.OpenPunctuation },
+ { "Pe", UnicodeCategory.ClosePunctuation },
+ { "Pi", UnicodeCategory.InitialQuotePunctuation },
+ { "Pf", UnicodeCategory.FinalQuotePunctuation },
+ { "Po", UnicodeCategory.OtherPunctuation },
+ { "Sm", UnicodeCategory.MathSymbol },
+ { "Sc", UnicodeCategory.CurrencySymbol },
+ { "Sk", UnicodeCategory.ModifierSymbol },
+ { "So", UnicodeCategory.OtherSymbol },
+ { "Zs", UnicodeCategory.SpaceSeparator },
+ { "Zl", UnicodeCategory.LineSeparator },
+ { "Zp", UnicodeCategory.ParagraphSeparator },
+ { "Cc", UnicodeCategory.Control },
+ { "Cf", UnicodeCategory.Format },
+ { "Cs", UnicodeCategory.Surrogate },
+ { "Co", UnicodeCategory.PrivateUse },
+ };
+
+ private static readonly Dictionary<uint, UnicodeCategory> _categoryMap = new Dictionary<uint, UnicodeCategory>();
+ private static readonly Dictionary<uint, CharProperty> _propertyMap = new Dictionary<uint, CharProperty>();
+ private static readonly Dictionary<uint, uint> _simpleCaseFoldMap = new Dictionary<uint, uint>();
+ private static readonly Dictionary<uint, uint> _simpleLowerCaseMap = new Dictionary<uint, uint>();
+ private static readonly Dictionary<uint, uint> _simpleTitleCaseMap = new Dictionary<uint, uint>();
+ private static readonly Dictionary<uint, uint> _simpleUpperCaseMap = new Dictionary<uint, uint>();
+
+ static UnicodeData()
+ {
+ static IEnumerable<string> ReadAllLines(string resourceName)
+ {
+ using (Stream stream = typeof(UnicodeData).Assembly.GetManifestResourceStream(resourceName))
+ {
+ if (stream is null)
+ {
+ throw new XunitException($"Could not locate resource stream {resourceName} in the assembly.");
+ }
+
+ List<string> allLines = new List<string>();
+
+ using (StreamReader reader = new StreamReader(stream))
+ {
+ string nextLine;
+ while ((nextLine = reader.ReadLine()) != null)
+ {
+ yield return nextLine;
+ }
+ }
+ }
+ }
+
+ // First, read the basic category, bidi data, and simple upper / lower / title mappings from UnicodeData.txt
+ // File format is documented at https://www.unicode.org/reports/tr44/#UnicodeData.txt
+
+ string nameOfCurrentRange = null;
+ uint startOfCurrentRange = 0;
+
+ foreach (string line in ReadAllLines(UnicodeDataFilename))
+ {
+ string[] splitLine = line.Split(';');
+ Assert.Equal(15, splitLine.Length); // expected 15 segments resulting from the split
+
+ uint currentCodePoint = uint.Parse(splitLine[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+ string codePointName = splitLine[1];
+ string category = splitLine[2];
+
+ // Is this the start of a range?
+ // If so, save this data and keep iterating.
+
+ if (codePointName.EndsWith(", First>", StringComparison.Ordinal))
+ {
+ startOfCurrentRange = currentCodePoint;
+ nameOfCurrentRange = codePointName[..^(", First>".Length)];
+ continue;
+ }
+
+ // If we didn't see a <..., First> range immediately before
+ // this, assume it's a range of length 1.
+
+ if (codePointName != nameOfCurrentRange + ", Last>")
+ {
+ startOfCurrentRange = currentCodePoint;
+ }
+
+ uint.TryParse(splitLine[12], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint simpleUpperMapping);
+ uint.TryParse(splitLine[13], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint simpleLowerMapping);
+ uint.TryParse(splitLine[14], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint simpleTitleMapping);
+
+ for (uint i = startOfCurrentRange; i <= currentCodePoint; i++)
+ {
+ _categoryMap[i] = _categoryCodeMap[category];
+
+ if (simpleLowerMapping != 0)
+ {
+ _simpleLowerCaseMap[i] = simpleLowerMapping;
+ }
+
+ if (simpleUpperMapping != 0)
+ {
+ _simpleUpperCaseMap[i] = simpleUpperMapping;
+ }
+
+ if (simpleTitleMapping != 0)
+ {
+ _simpleTitleCaseMap[i] = simpleTitleMapping;
+ }
+ }
+ }
+
+ // Then, read the property map from PropList.txt.
+ // We're looking for lines of the form "XXXX[..YYYY] ; <prop> # <comment>"
+
+ Regex propListRegex = new Regex(@"^\s*(?<firstCodePoint>[0-9A-F]{4,})(\.\.(?<lastCodePoint>[0-9A-F]{4,}))?\s*;\s*(?<propName>\w+)\s*#", RegexOptions.IgnoreCase);
+
+ foreach (string line in ReadAllLines(PropListFilename))
+ {
+ Match match = propListRegex.Match(line);
+ if (!match.Success)
+ {
+ continue; // line was blank or was comment-only
+ }
+
+ uint firstCodePoint = uint.Parse(match.Groups["firstCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+ if (!uint.TryParse(match.Groups["lastCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint lastCodePoint))
+ {
+ lastCodePoint = firstCodePoint; // If not "XXXX..YYYY", assume "XXXX..XXXX"
+ }
+ CharProperty property = Enum.Parse<CharProperty>(match.Groups["propName"].Value);
+
+ for (uint i = firstCodePoint; i <= lastCodePoint; i++)
+ {
+ _propertyMap.TryGetValue(i, out CharProperty existingValue);
+ _propertyMap[i] = existingValue | property; // remember, this is flags
+ }
+ }
+
+ // Finally, read the case fold map from CaseFolding.txt.
+ // We're looking for lines of the form "<code>; <status>; <mapping>; # <name>", where <status> is 'C' or 'S'
+
+ Regex caseFoldRegex = new Regex(@"^\s*(?<fromCodePoint>[0-9A-F]{4,}); [CS]; (?<toCodePoint>[0-9A-F]{4,});", RegexOptions.IgnoreCase);
+
+ foreach (string line in ReadAllLines(CaseFoldingFilename))
+ {
+ Match match = caseFoldRegex.Match(line);
+ if (!match.Success)
+ {
+ continue; // line was blank, comment-only, or not simple / common
+ }
+
+ uint fromCodePoint = uint.Parse(match.Groups["fromCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+ uint toCodePoint = uint.Parse(match.Groups["toCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+
+ _simpleCaseFoldMap[fromCodePoint] = toCodePoint;
+ }
+ }
+
+ public static UnicodeCategory GetUnicodeCategory(uint codePoint)
+ {
+ Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
+
+ return _categoryMap.TryGetValue(codePoint, out UnicodeCategory category) ? category : UnicodeCategory.OtherNotAssigned;
+ }
+
+ public static bool IsLetter(uint codePoint)
+ {
+ switch (GetUnicodeCategory(codePoint))
+ {
+ case UnicodeCategory.UppercaseLetter:
+ case UnicodeCategory.LowercaseLetter:
+ case UnicodeCategory.TitlecaseLetter:
+ case UnicodeCategory.ModifierLetter:
+ case UnicodeCategory.OtherLetter:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ // Returns true iff code point is listed at https://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:whitespace:]
+ public static bool IsWhiteSpace(uint codePoint)
+ {
+ Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
+
+ _propertyMap.TryGetValue(codePoint, out CharProperty property);
+ return property.HasFlag(CharProperty.White_Space);
+ }
+
+ public static uint SimpleFoldCaseMap(uint codePoint)
+ {
+ Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
+
+ // If an entry doesn't exist, the value maps to itself.
+ return _simpleCaseFoldMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
+ }
+
+ public static uint SimpleLowerCaseMap(uint codePoint)
+ {
+ Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
+
+ // If an entry doesn't exist, the value maps to itself.
+ return _simpleLowerCaseMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
+ }
+
+ public static uint SimpleTitleCaseMap(uint codePoint)
+ {
+ Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
+
+ // If an entry doesn't exist, the value maps to itself.
+ return _simpleTitleCaseMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
+ }
+
+ public static uint SimpleUpperCaseMap(uint codePoint)
+ {
+ Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
+
+ // If an entry doesn't exist, the value maps to itself.
+ return _simpleUpperCaseMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
+ }
+
+ [Flags]
+ private enum CharProperty : ulong
+ {
+ ASCII_Hex_Digit = 1ul << 0,
+ Bidi_Control = 1ul << 1,
+ Dash = 1ul << 2,
+ Deprecated = 1ul << 3,
+ Diacritic = 1ul << 4,
+ Extender = 1ul << 5,
+ Hex_Digit = 1ul << 6,
+ Hyphen = 1ul << 7,
+ Ideographic = 1ul << 8,
+ IDS_Binary_Operator = 1ul << 9,
+ IDS_Trinary_Operator = 1ul << 10,
+ Join_Control = 1ul << 11,
+ Logical_Order_Exception = 1ul << 12,
+ Noncharacter_Code_Point = 1ul << 13,
+ Other_Alphabetic = 1ul << 14,
+ Other_Default_Ignorable_Code_Point = 1ul << 15,
+ Other_Grapheme_Extend = 1ul << 16,
+ Other_ID_Continue = 1ul << 17,
+ Other_ID_Start = 1ul << 18,
+ Other_Lowercase = 1ul << 19,
+ Other_Math = 1ul << 20,
+ Other_Uppercase = 1ul << 21,
+ Pattern_Syntax = 1ul << 22,
+ Pattern_White_Space = 1ul << 23,
+ Prepended_Concatenation_Mark = 1ul << 24,
+ Quotation_Mark = 1ul << 25,
+ Radical = 1ul << 26,
+ Regional_Indicator = 1ul << 27,
+ Sentence_Terminal = 1ul << 28,
+ Soft_Dotted = 1ul << 29,
+ Terminal_Punctuation = 1ul << 30,
+ Unified_Ideograph = 1ul << 31,
+ Variation_Selector = 1ul << 32,
+ White_Space = 1ul << 33,
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Text.RegularExpressions;
-using Xunit;
-using Xunit.Sdk;
-
-namespace System.Text.Unicode.Tests
-{
- /*
- * This file contains helpers for parsing the Unicode data files, which we can then use to test
- * our Framework's implementations of various character & text processing routines.
- */
-
- public static class UnicodeData
- {
- private const string UnicodeDataFilename = "UnicodeData.11.0.txt";
- private const string CaseFoldingFilename = "CaseFolding-12.1.0.txt";
- private const string PropListFilename = "PropList-12.1.0.txt";
-
- private static readonly Dictionary<string, UnicodeCategory> _categoryCodeMap = new Dictionary<string, UnicodeCategory>()
- {
- { "Lu", UnicodeCategory.UppercaseLetter },
- { "Ll", UnicodeCategory.LowercaseLetter },
- { "Lt", UnicodeCategory.TitlecaseLetter },
- { "Lm", UnicodeCategory.ModifierLetter },
- { "Lo", UnicodeCategory.OtherLetter },
- { "Mn", UnicodeCategory.NonSpacingMark },
- { "Mc", UnicodeCategory.SpacingCombiningMark },
- { "Me", UnicodeCategory.EnclosingMark },
- { "Nd", UnicodeCategory.DecimalDigitNumber },
- { "Nl", UnicodeCategory.LetterNumber },
- { "No", UnicodeCategory.OtherNumber },
- { "Pc", UnicodeCategory.ConnectorPunctuation },
- { "Pd", UnicodeCategory.DashPunctuation },
- { "Ps", UnicodeCategory.OpenPunctuation },
- { "Pe", UnicodeCategory.ClosePunctuation },
- { "Pi", UnicodeCategory.InitialQuotePunctuation },
- { "Pf", UnicodeCategory.FinalQuotePunctuation },
- { "Po", UnicodeCategory.OtherPunctuation },
- { "Sm", UnicodeCategory.MathSymbol },
- { "Sc", UnicodeCategory.CurrencySymbol },
- { "Sk", UnicodeCategory.ModifierSymbol },
- { "So", UnicodeCategory.OtherSymbol },
- { "Zs", UnicodeCategory.SpaceSeparator },
- { "Zl", UnicodeCategory.LineSeparator },
- { "Zp", UnicodeCategory.ParagraphSeparator },
- { "Cc", UnicodeCategory.Control },
- { "Cf", UnicodeCategory.Format },
- { "Cs", UnicodeCategory.Surrogate },
- { "Co", UnicodeCategory.PrivateUse },
- };
-
- private static readonly Dictionary<uint, UnicodeCategory> _categoryMap = new Dictionary<uint, UnicodeCategory>();
- private static readonly Dictionary<uint, CharProperty> _propertyMap = new Dictionary<uint, CharProperty>();
- private static readonly Dictionary<uint, uint> _simpleCaseFoldMap = new Dictionary<uint, uint>();
- private static readonly Dictionary<uint, uint> _simpleLowerCaseMap = new Dictionary<uint, uint>();
- private static readonly Dictionary<uint, uint> _simpleTitleCaseMap = new Dictionary<uint, uint>();
- private static readonly Dictionary<uint, uint> _simpleUpperCaseMap = new Dictionary<uint, uint>();
-
- static UnicodeData()
- {
- static IEnumerable<string> ReadAllLines(string resourceName)
- {
- using (Stream stream = typeof(UnicodeData).Assembly.GetManifestResourceStream(resourceName))
- {
- if (stream is null)
- {
- throw new XunitException($"Could not locate resource stream {resourceName} in the assembly.");
- }
-
- List<string> allLines = new List<string>();
-
- using (StreamReader reader = new StreamReader(stream))
- {
- string nextLine;
- while ((nextLine = reader.ReadLine()) != null)
- {
- yield return nextLine;
- }
- }
- }
- }
-
- // First, read the basic category, bidi data, and simple upper / lower / title mappings from UnicodeData.txt
- // File format is documented at https://www.unicode.org/reports/tr44/#UnicodeData.txt
-
- string nameOfCurrentRange = null;
- uint startOfCurrentRange = 0;
-
- foreach (string line in ReadAllLines(UnicodeDataFilename))
- {
- string[] splitLine = line.Split(';');
- Assert.Equal(15, splitLine.Length); // expected 15 segments resulting from the split
-
- uint currentCodePoint = uint.Parse(splitLine[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture);
- string codePointName = splitLine[1];
- string category = splitLine[2];
-
- // Is this the start of a range?
- // If so, save this data and keep iterating.
-
- if (codePointName.EndsWith(", First>", StringComparison.Ordinal))
- {
- startOfCurrentRange = currentCodePoint;
- nameOfCurrentRange = codePointName[..^(", First>".Length)];
- continue;
- }
-
- // If we didn't see a <..., First> range immediately before
- // this, assume it's a range of length 1.
-
- if (codePointName != nameOfCurrentRange + ", Last>")
- {
- startOfCurrentRange = currentCodePoint;
- }
-
- uint.TryParse(splitLine[12], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint simpleUpperMapping);
- uint.TryParse(splitLine[13], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint simpleLowerMapping);
- uint.TryParse(splitLine[14], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint simpleTitleMapping);
-
- for (uint i = startOfCurrentRange; i <= currentCodePoint; i++)
- {
- _categoryMap[i] = _categoryCodeMap[category];
-
- if (simpleLowerMapping != 0)
- {
- _simpleLowerCaseMap[i] = simpleLowerMapping;
- }
-
- if (simpleUpperMapping != 0)
- {
- _simpleUpperCaseMap[i] = simpleUpperMapping;
- }
-
- if (simpleTitleMapping != 0)
- {
- _simpleTitleCaseMap[i] = simpleTitleMapping;
- }
- }
- }
-
- // Then, read the property map from PropList.txt.
- // We're looking for lines of the form "XXXX[..YYYY] ; <prop> # <comment>"
-
- Regex propListRegex = new Regex(@"^\s*(?<firstCodePoint>[0-9A-F]{4,})(\.\.(?<lastCodePoint>[0-9A-F]{4,}))?\s*;\s*(?<propName>\w+)\s*#", RegexOptions.IgnoreCase);
-
- foreach (string line in ReadAllLines(PropListFilename))
- {
- Match match = propListRegex.Match(line);
- if (!match.Success)
- {
- continue; // line was blank or was comment-only
- }
-
- uint firstCodePoint = uint.Parse(match.Groups["firstCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
- if (!uint.TryParse(match.Groups["lastCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint lastCodePoint))
- {
- lastCodePoint = firstCodePoint; // If not "XXXX..YYYY", assume "XXXX..XXXX"
- }
- CharProperty property = Enum.Parse<CharProperty>(match.Groups["propName"].Value);
-
- for (uint i = firstCodePoint; i <= lastCodePoint; i++)
- {
- _propertyMap.TryGetValue(i, out CharProperty existingValue);
- _propertyMap[i] = existingValue | property; // remember, this is flags
- }
- }
-
- // Finally, read the case fold map from CaseFolding.txt.
- // We're looking for lines of the form "<code>; <status>; <mapping>; # <name>", where <status> is 'C' or 'S'
-
- Regex caseFoldRegex = new Regex(@"^\s*(?<fromCodePoint>[0-9A-F]{4,}); [CS]; (?<toCodePoint>[0-9A-F]{4,});", RegexOptions.IgnoreCase);
-
- foreach (string line in ReadAllLines(CaseFoldingFilename))
- {
- Match match = caseFoldRegex.Match(line);
- if (!match.Success)
- {
- continue; // line was blank, comment-only, or not simple / common
- }
-
- uint fromCodePoint = uint.Parse(match.Groups["fromCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
- uint toCodePoint = uint.Parse(match.Groups["toCodePoint"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
-
- _simpleCaseFoldMap[fromCodePoint] = toCodePoint;
- }
- }
-
- public static UnicodeCategory GetUnicodeCategory(uint codePoint)
- {
- Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
-
- return _categoryMap.TryGetValue(codePoint, out UnicodeCategory category) ? category : UnicodeCategory.OtherNotAssigned;
- }
-
- public static bool IsLetter(uint codePoint)
- {
- switch (GetUnicodeCategory(codePoint))
- {
- case UnicodeCategory.UppercaseLetter:
- case UnicodeCategory.LowercaseLetter:
- case UnicodeCategory.TitlecaseLetter:
- case UnicodeCategory.ModifierLetter:
- case UnicodeCategory.OtherLetter:
- return true;
-
- default:
- return false;
- }
- }
-
- // Returns true iff code point is listed at https://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:whitespace:]
- public static bool IsWhiteSpace(uint codePoint)
- {
- Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
-
- _propertyMap.TryGetValue(codePoint, out CharProperty property);
- return property.HasFlag(CharProperty.White_Space);
- }
-
- public static uint SimpleFoldCaseMap(uint codePoint)
- {
- Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
-
- // If an entry doesn't exist, the value maps to itself.
- return _simpleCaseFoldMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
- }
-
- public static uint SimpleLowerCaseMap(uint codePoint)
- {
- Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
-
- // If an entry doesn't exist, the value maps to itself.
- return _simpleLowerCaseMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
- }
-
- public static uint SimpleTitleCaseMap(uint codePoint)
- {
- Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
-
- // If an entry doesn't exist, the value maps to itself.
- return _simpleTitleCaseMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
- }
-
- public static uint SimpleUpperCaseMap(uint codePoint)
- {
- Assert.True(codePoint <= 0x10FFFF, "Invalid code point provided.");
-
- // If an entry doesn't exist, the value maps to itself.
- return _simpleUpperCaseMap.TryGetValue(codePoint, out uint value) ? value : codePoint;
- }
-
- [Flags]
- private enum CharProperty : ulong
- {
- ASCII_Hex_Digit = 1ul << 0,
- Bidi_Control = 1ul << 1,
- Dash = 1ul << 2,
- Deprecated = 1ul << 3,
- Diacritic = 1ul << 4,
- Extender = 1ul << 5,
- Hex_Digit = 1ul << 6,
- Hyphen = 1ul << 7,
- Ideographic = 1ul << 8,
- IDS_Binary_Operator = 1ul << 9,
- IDS_Trinary_Operator = 1ul << 10,
- Join_Control = 1ul << 11,
- Logical_Order_Exception = 1ul << 12,
- Noncharacter_Code_Point = 1ul << 13,
- Other_Alphabetic = 1ul << 14,
- Other_Default_Ignorable_Code_Point = 1ul << 15,
- Other_Grapheme_Extend = 1ul << 16,
- Other_ID_Continue = 1ul << 17,
- Other_ID_Start = 1ul << 18,
- Other_Lowercase = 1ul << 19,
- Other_Math = 1ul << 20,
- Other_Uppercase = 1ul << 21,
- Pattern_Syntax = 1ul << 22,
- Pattern_White_Space = 1ul << 23,
- Prepended_Concatenation_Mark = 1ul << 24,
- Quotation_Mark = 1ul << 25,
- Radical = 1ul << 26,
- Regional_Indicator = 1ul << 27,
- Sentence_Terminal = 1ul << 28,
- Soft_Dotted = 1ul << 29,
- Terminal_Punctuation = 1ul << 30,
- Unified_Ideograph = 1ul << 31,
- Variation_Selector = 1ul << 32,
- White_Space = 1ul << 33,
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Globalization;
+using System.Linq;
+using System.Numerics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.Text.Unicode.Tests
+{
+ public class Utf16UtilityTests
+ {
+ private unsafe delegate char* GetPointerToFirstInvalidCharDel(char* pInputBuffer, int inputLength, out long utf8CodeUnitCountAdjustment, out int scalarCountAdjustment);
+ private static readonly Lazy<GetPointerToFirstInvalidCharDel> _getPointerToFirstInvalidCharFn = CreateGetPointerToFirstInvalidCharFn();
+
+ [Theory]
+ [InlineData("", 0, 0)] // empty string is OK
+ [InlineData("X", 1, 1)]
+ [InlineData("XY", 2, 2)]
+ [InlineData("XYZ", 3, 3)]
+ [InlineData("<EACU>", 1, 2)]
+ [InlineData("X<EACU>", 2, 3)]
+ [InlineData("<EACU>X", 2, 3)]
+ [InlineData("<EURO>", 1, 3)]
+ [InlineData("<GRIN>", 1, 4)]
+ [InlineData("X<GRIN>Z", 3, 6)]
+ [InlineData("X<0000>Z", 3, 3)] // null chars are allowed
+ public void GetIndexOfFirstInvalidUtf16Sequence_WithSmallValidBuffers(string unprocessedInput, int expectedRuneCount, int expectedUtf8ByteCount)
+ {
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(unprocessedInput, -1 /* expectedIdxOfFirstInvalidChar */, expectedRuneCount, expectedUtf8ByteCount);
+ }
+
+ [Theory]
+ [InlineData("<DC00>", 0, 0, 0)] // standalone low surrogate (at beginning of sequence)
+ [InlineData("X<DC00>", 1, 1, 1)] // standalone low surrogate (preceded by valid ASCII data)
+ [InlineData("<EURO><DC00>", 1, 1, 3)] // standalone low surrogate (preceded by valid non-ASCII data)
+ [InlineData("<D800>", 0, 0, 0)] // standalone high surrogate (missing follow-up low surrogate)
+ [InlineData("<D800>Y", 0, 0, 0)] // standalone high surrogate (followed by ASCII char)
+ [InlineData("<D800><D800>", 0, 0, 0)] // standalone high surrogate (followed by high surrogate)
+ [InlineData("<D800><EURO>", 0, 0, 0)] // standalone high surrogate (followed by valid non-ASCII char)
+ [InlineData("<DC00><DC00>", 0, 0, 0)] // standalone low surrogate (not preceded by a high surrogate)
+ [InlineData("<DC00><D800>", 0, 0, 0)] // standalone low surrogate (not preceded by a high surrogate)
+ [InlineData("<GRIN><DC00><DC00>", 2, 1, 4)] // standalone low surrogate (preceded by a valid surrogate pair)
+ [InlineData("<GRIN><DC00><D800>", 2, 1, 4)] // standalone low surrogate (preceded by a valid surrogate pair)
+ [InlineData("<GRIN><0000><DC00><D800>", 3, 2, 5)] // standalone low surrogate (preceded by a valid null char)
+ public void GetIndexOfFirstInvalidUtf16Sequence_WithSmallInvalidBuffers(string unprocessedInput, int idxOfFirstInvalidChar, int expectedRuneCount, int expectedUtf8ByteCount)
+ {
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(unprocessedInput, idxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
+ }
+
+ [Theory] // chars below presented as hex since Xunit doesn't like invalid UTF-16 string literals
+ [InlineData("<2BB4><218C><1BC0><613F><F9E9><B740><DE38><E689>", 6, 6, 18)]
+ [InlineData("<1854><C980><012C><4797><DD5A><41D0><A104><5464>", 4, 4, 11)]
+ [InlineData("<F1AF><8BD3><5037><BE29><DEFF><3E3A><DD71><6336>", 4, 4, 12)]
+ [InlineData("<B978><0F25><DC23><D3BB><7352><4025><0B93><4107>", 2, 2, 6)]
+ [InlineData("<887C><C980><012C><4797><DD5A><41D0><A104><5464>", 4, 4, 11)]
+ public void GetIndexOfFirstInvalidUtf16Sequence_WithEightRandomCharsContainingUnpairedSurrogates(string unprocessedInput, int idxOfFirstInvalidChar, int expectedRuneCount, int expectedUtf8ByteCount)
+ {
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(unprocessedInput, idxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf16Sequence_WithInvalidSurrogateSequences()
+ {
+ // All ASCII
+
+ char[] chars = Enumerable.Repeat('x', 128).ToArray();
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 128, expectedUtf8ByteCount: 128);
+
+ // Throw a surrogate pair at the beginning
+
+ chars[0] = '\uD800';
+ chars[1] = '\uDFFF';
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 127, expectedUtf8ByteCount: 130);
+
+ // Throw a surrogate pair near the end
+
+ chars[124] = '\uD800';
+ chars[125] = '\uDFFF';
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 126, expectedUtf8ByteCount: 132);
+
+ // Throw a standalone surrogate code point at the *very* end
+
+ chars[127] = '\uD800'; // high surrogate
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 127, expectedRuneCount: 125, expectedUtf8ByteCount: 131);
+
+ chars[127] = '\uDFFF'; // low surrogate
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 127, expectedRuneCount: 125, expectedUtf8ByteCount: 131);
+
+ // Make the final surrogate pair valid
+
+ chars[126] = '\uD800'; // high surrogate
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 125, expectedUtf8ByteCount: 134);
+
+ // Throw an invalid surrogate sequence in the middle (straddles a vector boundary)
+
+ chars[12] = '\u0080'; // 2-byte UTF-8 sequence
+ chars[13] = '\uD800'; // high surrogate
+ chars[14] = '\uD800'; // high surrogate
+ chars[15] = '\uDFFF'; // low surrogate
+ chars[16] = '\uDFFF'; // low surrogate
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 13, expectedRuneCount: 12, expectedUtf8ByteCount: 16);
+
+ // Correct the surrogate sequence we just added
+
+ chars[14] = '\uDC00'; // low surrogate
+ chars[15] = '\uDBFF'; // high surrogate
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 123, expectedUtf8ByteCount: 139);
+
+ // Corrupt the surrogate pair that's split across a vector boundary
+
+ chars[16] = 'x'; // ASCII char (remember.. chars[15] is a high surrogate char)
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 15, expectedRuneCount: 13, expectedUtf8ByteCount: 20);
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf16Sequence_WithStandaloneLowSurrogateCharAtStart()
+ {
+ // The input stream will be a vector's worth of ASCII chars, followed by a single standalone low
+ // surrogate char, then padded with U+0000 until it's a multiple of the vector size.
+ // Using Vector<ushort>.Count here as a stand-in for Vector<char>.Count.
+
+ char[] chars = new char[Vector<ushort>.Count * 2];
+ for (int i = 0; i < Vector<ushort>.Count; i++)
+ {
+ chars[i] = 'x'; // ASCII char
+ }
+
+ chars[Vector<ushort>.Count] = '\uDEAD'; // standalone low surrogate char
+
+ for (int i = 0; i <= Vector<ushort>.Count; i++)
+ {
+ // Expect all ASCII chars to be consumed, low surrogate char to be marked invalid.
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars[(Vector<ushort>.Count - i)..], i, i, i);
+ }
+ }
+
+ private static void GetIndexOfFirstInvalidUtf16Sequence_Test_Core(string unprocessedInput, int expectedIdxOfFirstInvalidChar, int expectedRuneCount, long expectedUtf8ByteCount)
+ {
+ char[] processedInput = ProcessInput(unprocessedInput).ToCharArray();
+
+ // Run the test normally
+
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
+
+ // Put a bunch of ASCII data at the beginning (to test the call to ASCIIUtility at method entry)
+
+ processedInput = Enumerable.Repeat('x', 128).Concat(processedInput).ToArray();
+
+ if (expectedIdxOfFirstInvalidChar >= 0)
+ {
+ expectedIdxOfFirstInvalidChar += 128;
+ }
+ expectedRuneCount += 128;
+ expectedUtf8ByteCount += 128;
+
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
+
+ // Change the first few chars to a mixture of 2-byte and 3-byte UTF-8 sequences
+ // This makes sure the vectorized code paths can properly handle these.
+
+ processedInput[0] = '\u0080'; // 2-byte UTF-8 sequence
+ processedInput[1] = '\u0800'; // 3-byte UTF-8 sequence
+ processedInput[2] = '\u0080'; // 2-byte UTF-8 sequence
+ processedInput[3] = '\u0800'; // 3-byte UTF-8 sequence
+ processedInput[4] = '\u0080'; // 2-byte UTF-8 sequence
+ processedInput[5] = '\u0800'; // 3-byte UTF-8 sequence
+ processedInput[6] = '\u0080'; // 2-byte UTF-8 sequence
+ processedInput[7] = '\u0800'; // 3-byte UTF-8 sequence
+
+ expectedUtf8ByteCount += 12;
+
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
+
+ // Throw some surrogate pairs into the mix to make sure they're also handled properly
+ // by the vectorized code paths.
+
+ processedInput[8] = '\u0080'; // 2-byte UTF-8 sequence
+ processedInput[9] = '\u0800'; // 3-byte UTF-8 sequence
+ processedInput[10] = '\u0080'; // 2-byte UTF-8 sequence
+ processedInput[11] = '\u0800'; // 3-byte UTF-8 sequence
+ processedInput[12] = '\u0080'; // 2-byte UTF-8 sequence
+ processedInput[13] = '\uD800'; // high surrogate
+ processedInput[14] = '\uDC00'; // low surrogate
+ processedInput[15] = 'z'; // ASCII char
+
+ expectedRuneCount--;
+ expectedUtf8ByteCount += 9;
+
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
+
+ // Split the next surrogate pair across the vector boundary (so that we
+ // don't inadvertently treat this as a standalone surrogate sequence).
+
+ processedInput[15] = '\uDBFF'; // high surrogate
+ processedInput[16] = '\uDFFF'; // low surrogate
+
+ expectedRuneCount--;
+ expectedUtf8ByteCount += 2;
+
+ GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
+ }
+
+ private static unsafe void GetIndexOfFirstInvalidUtf16Sequence_Test_Core(char[] input, int expectedRetVal, int expectedRuneCount, long expectedUtf8ByteCount)
+ {
+ // Arrange
+
+ using BoundedMemory<char> boundedMemory = BoundedMemory.AllocateFromExistingData(input);
+ boundedMemory.MakeReadonly();
+
+ // Act
+
+ int actualRetVal;
+ long actualUtf8CodeUnitCount;
+ int actualRuneCount;
+
+ fixed (char* pInputBuffer = &MemoryMarshal.GetReference(boundedMemory.Span))
+ {
+ char* pFirstInvalidChar = _getPointerToFirstInvalidCharFn.Value(pInputBuffer, input.Length, out long utf8CodeUnitCountAdjustment, out int scalarCountAdjustment);
+
+ long ptrDiff = pFirstInvalidChar - pInputBuffer;
+ Assert.True((ulong)ptrDiff <= (uint)input.Length, "ptrDiff was outside expected range.");
+
+ Assert.True(utf8CodeUnitCountAdjustment >= 0, "UTF-16 code unit count adjustment must be non-negative.");
+ Assert.True(scalarCountAdjustment <= 0, "Scalar count adjustment must be 0 or negative.");
+
+ actualRetVal = (ptrDiff == input.Length) ? -1 : (int)ptrDiff;
+
+ // The last two 'out' parameters are:
+ // a) The number to be added to the "chars processed" return value to come up with the total UTF-8 code unit count, and
+ // b) The number to be added to the "total UTF-16 code unit count" value to come up with the total scalar count.
+
+ actualUtf8CodeUnitCount = ptrDiff + utf8CodeUnitCountAdjustment;
+ actualRuneCount = (int)ptrDiff + scalarCountAdjustment;
+ }
+
+ // Assert
+
+ Assert.Equal(expectedRetVal, actualRetVal);
+ Assert.Equal(expectedRuneCount, actualRuneCount);
+ Assert.Equal(actualUtf8CodeUnitCount, expectedUtf8ByteCount);
+ }
+
+ private static Lazy<GetPointerToFirstInvalidCharDel> CreateGetPointerToFirstInvalidCharFn()
+ {
+ return new Lazy<GetPointerToFirstInvalidCharDel>(() =>
+ {
+ Type utf16UtilityType = typeof(Utf8).Assembly.GetType("System.Text.Unicode.Utf16Utility");
+
+ if (utf16UtilityType is null)
+ {
+ throw new Exception("Couldn't find Utf16Utility type in System.Private.CoreLib.");
+ }
+
+ MethodInfo methodInfo = utf16UtilityType.GetMethod("GetPointerToFirstInvalidChar", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
+
+ if (methodInfo is null)
+ {
+ throw new Exception("Couldn't find GetPointerToFirstInvalidChar method on Utf8Utility.");
+ }
+
+ return (GetPointerToFirstInvalidCharDel)methodInfo.CreateDelegate(typeof(GetPointerToFirstInvalidCharDel));
+ });
+ }
+
+ private static string ProcessInput(string input)
+ {
+ input = input.Replace("<EACU>", "\u00E9", StringComparison.Ordinal); // U+00E9 LATIN SMALL LETTER E WITH ACUTE
+ input = input.Replace("<EURO>", "\u20AC", StringComparison.Ordinal); // U+20AC EURO SIGN
+ input = input.Replace("<GRIN>", "\U0001F600", StringComparison.Ordinal); // U+1F600 GRINNING FACE
+
+ // Replace <ABCD> with \uABCD. This allows us to flow potentially malformed
+ // UTF-16 strings without Xunit. (The unit testing framework gets angry when
+ // we try putting invalid UTF-16 data as inline test data.)
+
+ int idx;
+ while ((idx = input.IndexOf('<')) >= 0)
+ {
+ input = input[..idx] + (char)ushort.Parse(input.Substring(idx + 1, 4), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture) + input[(idx + 6)..];
+ }
+
+ return input;
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Globalization;
-using System.Linq;
-using System.Numerics;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using Xunit;
-
-namespace System.Text.Unicode.Tests
-{
- public partial class Utf16UtilityTests
- {
- private unsafe delegate char* GetPointerToFirstInvalidCharDel(char* pInputBuffer, int inputLength, out long utf8CodeUnitCountAdjustment, out int scalarCountAdjustment);
- private static readonly Lazy<GetPointerToFirstInvalidCharDel> _getPointerToFirstInvalidCharFn = CreateGetPointerToFirstInvalidCharFn();
-
- [Theory]
- [InlineData("", 0, 0)] // empty string is OK
- [InlineData("X", 1, 1)]
- [InlineData("XY", 2, 2)]
- [InlineData("XYZ", 3, 3)]
- [InlineData("<EACU>", 1, 2)]
- [InlineData("X<EACU>", 2, 3)]
- [InlineData("<EACU>X", 2, 3)]
- [InlineData("<EURO>", 1, 3)]
- [InlineData("<GRIN>", 1, 4)]
- [InlineData("X<GRIN>Z", 3, 6)]
- [InlineData("X<0000>Z", 3, 3)] // null chars are allowed
- public void GetIndexOfFirstInvalidUtf16Sequence_WithSmallValidBuffers(string unprocessedInput, int expectedRuneCount, int expectedUtf8ByteCount)
- {
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(unprocessedInput, -1 /* expectedIdxOfFirstInvalidChar */, expectedRuneCount, expectedUtf8ByteCount);
- }
-
- [Theory]
- [InlineData("<DC00>", 0, 0, 0)] // standalone low surrogate (at beginning of sequence)
- [InlineData("X<DC00>", 1, 1, 1)] // standalone low surrogate (preceded by valid ASCII data)
- [InlineData("<EURO><DC00>", 1, 1, 3)] // standalone low surrogate (preceded by valid non-ASCII data)
- [InlineData("<D800>", 0, 0, 0)] // standalone high surrogate (missing follow-up low surrogate)
- [InlineData("<D800>Y", 0, 0, 0)] // standalone high surrogate (followed by ASCII char)
- [InlineData("<D800><D800>", 0, 0, 0)] // standalone high surrogate (followed by high surrogate)
- [InlineData("<D800><EURO>", 0, 0, 0)] // standalone high surrogate (followed by valid non-ASCII char)
- [InlineData("<DC00><DC00>", 0, 0, 0)] // standalone low surrogate (not preceded by a high surrogate)
- [InlineData("<DC00><D800>", 0, 0, 0)] // standalone low surrogate (not preceded by a high surrogate)
- [InlineData("<GRIN><DC00><DC00>", 2, 1, 4)] // standalone low surrogate (preceded by a valid surrogate pair)
- [InlineData("<GRIN><DC00><D800>", 2, 1, 4)] // standalone low surrogate (preceded by a valid surrogate pair)
- [InlineData("<GRIN><0000><DC00><D800>", 3, 2, 5)] // standalone low surrogate (preceded by a valid null char)
- public void GetIndexOfFirstInvalidUtf16Sequence_WithSmallInvalidBuffers(string unprocessedInput, int idxOfFirstInvalidChar, int expectedRuneCount, int expectedUtf8ByteCount)
- {
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(unprocessedInput, idxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
- }
-
- [Theory] // chars below presented as hex since Xunit doesn't like invalid UTF-16 string literals
- [InlineData("<2BB4><218C><1BC0><613F><F9E9><B740><DE38><E689>", 6, 6, 18)]
- [InlineData("<1854><C980><012C><4797><DD5A><41D0><A104><5464>", 4, 4, 11)]
- [InlineData("<F1AF><8BD3><5037><BE29><DEFF><3E3A><DD71><6336>", 4, 4, 12)]
- [InlineData("<B978><0F25><DC23><D3BB><7352><4025><0B93><4107>", 2, 2, 6)]
- [InlineData("<887C><C980><012C><4797><DD5A><41D0><A104><5464>", 4, 4, 11)]
- public void GetIndexOfFirstInvalidUtf16Sequence_WithEightRandomCharsContainingUnpairedSurrogates(string unprocessedInput, int idxOfFirstInvalidChar, int expectedRuneCount, int expectedUtf8ByteCount)
- {
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(unprocessedInput, idxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf16Sequence_WithInvalidSurrogateSequences()
- {
- // All ASCII
-
- char[] chars = Enumerable.Repeat('x', 128).ToArray();
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 128, expectedUtf8ByteCount: 128);
-
- // Throw a surrogate pair at the beginning
-
- chars[0] = '\uD800';
- chars[1] = '\uDFFF';
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 127, expectedUtf8ByteCount: 130);
-
- // Throw a surrogate pair near the end
-
- chars[124] = '\uD800';
- chars[125] = '\uDFFF';
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 126, expectedUtf8ByteCount: 132);
-
- // Throw a standalone surrogate code point at the *very* end
-
- chars[127] = '\uD800'; // high surrogate
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 127, expectedRuneCount: 125, expectedUtf8ByteCount: 131);
-
- chars[127] = '\uDFFF'; // low surrogate
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 127, expectedRuneCount: 125, expectedUtf8ByteCount: 131);
-
- // Make the final surrogate pair valid
-
- chars[126] = '\uD800'; // high surrogate
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 125, expectedUtf8ByteCount: 134);
-
- // Throw an invalid surrogate sequence in the middle (straddles a vector boundary)
-
- chars[12] = '\u0080'; // 2-byte UTF-8 sequence
- chars[13] = '\uD800'; // high surrogate
- chars[14] = '\uD800'; // high surrogate
- chars[15] = '\uDFFF'; // low surrogate
- chars[16] = '\uDFFF'; // low surrogate
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 13, expectedRuneCount: 12, expectedUtf8ByteCount: 16);
-
- // Correct the surrogate sequence we just added
-
- chars[14] = '\uDC00'; // low surrogate
- chars[15] = '\uDBFF'; // high surrogate
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, -1, expectedRuneCount: 123, expectedUtf8ByteCount: 139);
-
- // Corrupt the surrogate pair that's split across a vector boundary
-
- chars[16] = 'x'; // ASCII char (remember.. chars[15] is a high surrogate char)
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars, 15, expectedRuneCount: 13, expectedUtf8ByteCount: 20);
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf16Sequence_WithStandaloneLowSurrogateCharAtStart()
- {
- // The input stream will be a vector's worth of ASCII chars, followed by a single standalone low
- // surrogate char, then padded with U+0000 until it's a multiple of the vector size.
- // Using Vector<ushort>.Count here as a stand-in for Vector<char>.Count.
-
- char[] chars = new char[Vector<ushort>.Count * 2];
- for (int i = 0; i < Vector<ushort>.Count; i++)
- {
- chars[i] = 'x'; // ASCII char
- }
-
- chars[Vector<ushort>.Count] = '\uDEAD'; // standalone low surrogate char
-
- for (int i = 0; i <= Vector<ushort>.Count; i++)
- {
- // Expect all ASCII chars to be consumed, low surrogate char to be marked invalid.
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(chars[(Vector<ushort>.Count - i)..], i, i, i);
- }
- }
-
- private static void GetIndexOfFirstInvalidUtf16Sequence_Test_Core(string unprocessedInput, int expectedIdxOfFirstInvalidChar, int expectedRuneCount, long expectedUtf8ByteCount)
- {
- char[] processedInput = ProcessInput(unprocessedInput).ToCharArray();
-
- // Run the test normally
-
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
-
- // Put a bunch of ASCII data at the beginning (to test the call to ASCIIUtility at method entry)
-
- processedInput = Enumerable.Repeat('x', 128).Concat(processedInput).ToArray();
-
- if (expectedIdxOfFirstInvalidChar >= 0)
- {
- expectedIdxOfFirstInvalidChar += 128;
- }
- expectedRuneCount += 128;
- expectedUtf8ByteCount += 128;
-
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
-
- // Change the first few chars to a mixture of 2-byte and 3-byte UTF-8 sequences
- // This makes sure the vectorized code paths can properly handle these.
-
- processedInput[0] = '\u0080'; // 2-byte UTF-8 sequence
- processedInput[1] = '\u0800'; // 3-byte UTF-8 sequence
- processedInput[2] = '\u0080'; // 2-byte UTF-8 sequence
- processedInput[3] = '\u0800'; // 3-byte UTF-8 sequence
- processedInput[4] = '\u0080'; // 2-byte UTF-8 sequence
- processedInput[5] = '\u0800'; // 3-byte UTF-8 sequence
- processedInput[6] = '\u0080'; // 2-byte UTF-8 sequence
- processedInput[7] = '\u0800'; // 3-byte UTF-8 sequence
-
- expectedUtf8ByteCount += 12;
-
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
-
- // Throw some surrogate pairs into the mix to make sure they're also handled properly
- // by the vectorized code paths.
-
- processedInput[8] = '\u0080'; // 2-byte UTF-8 sequence
- processedInput[9] = '\u0800'; // 3-byte UTF-8 sequence
- processedInput[10] = '\u0080'; // 2-byte UTF-8 sequence
- processedInput[11] = '\u0800'; // 3-byte UTF-8 sequence
- processedInput[12] = '\u0080'; // 2-byte UTF-8 sequence
- processedInput[13] = '\uD800'; // high surrogate
- processedInput[14] = '\uDC00'; // low surrogate
- processedInput[15] = 'z'; // ASCII char
-
- expectedRuneCount--;
- expectedUtf8ByteCount += 9;
-
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
-
- // Split the next surrogate pair across the vector boundary (so that we
- // don't inadvertently treat this as a standalone surrogate sequence).
-
- processedInput[15] = '\uDBFF'; // high surrogate
- processedInput[16] = '\uDFFF'; // low surrogate
-
- expectedRuneCount--;
- expectedUtf8ByteCount += 2;
-
- GetIndexOfFirstInvalidUtf16Sequence_Test_Core(processedInput, expectedIdxOfFirstInvalidChar, expectedRuneCount, expectedUtf8ByteCount);
- }
-
- private static unsafe void GetIndexOfFirstInvalidUtf16Sequence_Test_Core(char[] input, int expectedRetVal, int expectedRuneCount, long expectedUtf8ByteCount)
- {
- // Arrange
-
- using BoundedMemory<char> boundedMemory = BoundedMemory.AllocateFromExistingData(input);
- boundedMemory.MakeReadonly();
-
- // Act
-
- int actualRetVal;
- long actualUtf8CodeUnitCount;
- int actualRuneCount;
-
- fixed (char* pInputBuffer = &MemoryMarshal.GetReference(boundedMemory.Span))
- {
- char* pFirstInvalidChar = _getPointerToFirstInvalidCharFn.Value(pInputBuffer, input.Length, out long utf8CodeUnitCountAdjustment, out int scalarCountAdjustment);
-
- long ptrDiff = pFirstInvalidChar - pInputBuffer;
- Assert.True((ulong)ptrDiff <= (uint)input.Length, "ptrDiff was outside expected range.");
-
- Assert.True(utf8CodeUnitCountAdjustment >= 0, "UTF-16 code unit count adjustment must be non-negative.");
- Assert.True(scalarCountAdjustment <= 0, "Scalar count adjustment must be 0 or negative.");
-
- actualRetVal = (ptrDiff == input.Length) ? -1 : (int)ptrDiff;
-
- // The last two 'out' parameters are:
- // a) The number to be added to the "chars processed" return value to come up with the total UTF-8 code unit count, and
- // b) The number to be added to the "total UTF-16 code unit count" value to come up with the total scalar count.
-
- actualUtf8CodeUnitCount = ptrDiff + utf8CodeUnitCountAdjustment;
- actualRuneCount = (int)ptrDiff + scalarCountAdjustment;
- }
-
- // Assert
-
- Assert.Equal(expectedRetVal, actualRetVal);
- Assert.Equal(expectedRuneCount, actualRuneCount);
- Assert.Equal(actualUtf8CodeUnitCount, expectedUtf8ByteCount);
- }
-
- private static Lazy<GetPointerToFirstInvalidCharDel> CreateGetPointerToFirstInvalidCharFn()
- {
- return new Lazy<GetPointerToFirstInvalidCharDel>(() =>
- {
- Type utf16UtilityType = typeof(Utf8).Assembly.GetType("System.Text.Unicode.Utf16Utility");
-
- if (utf16UtilityType is null)
- {
- throw new Exception("Couldn't find Utf16Utility type in System.Private.CoreLib.");
- }
-
- MethodInfo methodInfo = utf16UtilityType.GetMethod("GetPointerToFirstInvalidChar", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
-
- if (methodInfo is null)
- {
- throw new Exception("Couldn't find GetPointerToFirstInvalidChar method on Utf8Utility.");
- }
-
- return (GetPointerToFirstInvalidCharDel)methodInfo.CreateDelegate(typeof(GetPointerToFirstInvalidCharDel));
- });
- }
-
- private static string ProcessInput(string input)
- {
- input = input.Replace("<EACU>", "\u00E9", StringComparison.Ordinal); // U+00E9 LATIN SMALL LETTER E WITH ACUTE
- input = input.Replace("<EURO>", "\u20AC", StringComparison.Ordinal); // U+20AC EURO SIGN
- input = input.Replace("<GRIN>", "\U0001F600", StringComparison.Ordinal); // U+1F600 GRINNING FACE
-
- // Replace <ABCD> with \uABCD. This allows us to flow potentially malformed
- // UTF-16 strings without Xunit. (The unit testing framework gets angry when
- // we try putting invalid UTF-16 data as inline test data.)
-
- int idx;
- while ((idx = input.IndexOf('<')) >= 0)
- {
- input = input[..idx] + (char)ushort.Parse(input.Substring(idx + 1, 4), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture) + input[(idx + 6)..];
- }
-
- return input;
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Linq;
-using Xunit;
-
-namespace System.Text.Unicode.Tests
-{
- public partial class Utf8Tests
- {
- [Theory]
- [InlineData("", "")] // empty string is OK
- [InlineData(X_UTF16, X_UTF8)]
- [InlineData(E_ACUTE_UTF16, E_ACUTE_UTF8)]
- [InlineData(EURO_SYMBOL_UTF16, EURO_SYMBOL_UTF8)]
- public void ToBytes_WithSmallValidBuffers(string utf16Input, string expectedUtf8TranscodingHex)
- {
- // These test cases are for the "slow processing" code path at the end of TranscodeToUtf8,
- // so inputs should be less than 2 chars.
-
- Assert.InRange(utf16Input.Length, 0, 1);
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: expectedUtf8TranscodingHex.Length / 2,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumCharsRead: utf16Input.Length,
- expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
- }
-
- [Theory]
- [InlineData("AB")] // 2 ASCII chars, hits fast inner loop
- [InlineData("ABCD")] // 4 ASCII chars, hits fast inner loop
- [InlineData("ABCDEF")] // 6 ASCII chars, hits fast inner loop
- [InlineData("ABCDEFGH")] // 8 ASCII chars, hits fast inner loop
- [InlineData("ABCDEFGHIJ")] // 10 ASCII chars, hits fast inner loop
- [InlineData("ABCDEF" + E_ACUTE_UTF16 + "HIJ")] // interrupts inner loop due to non-ASCII char in first char of first DWORD
- [InlineData("ABCDEFG" + EURO_SYMBOL_UTF16 + "IJ")] // interrupts inner loop due to non-ASCII char in second char of first DWORD
- [InlineData("ABCDEFGH" + E_ACUTE_UTF16 + "J")] // interrupts inner loop due to non-ASCII char in first char of second DWORD
- [InlineData("ABCDEFGHI" + EURO_SYMBOL_UTF16)] // interrupts inner loop due to non-ASCII char in second char of second DWORD
- [InlineData(X_UTF16 + E_ACUTE_UTF16)] // drains first ASCII char then falls down to slow path
- [InlineData(X_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // drains first ASCII char then consumes 2x 2-byte sequences at once
- [InlineData(E_ACUTE_UTF16 + X_UTF16)] // no first ASCII char to drain, consumes 2-byte seq followed by ASCII char
- [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // stay within 2x 2-byte sequence processing loop
- [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + X_UTF16)] // break out of 2x 2-byte seq loop due to ASCII data in second char of DWORD
- [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + X_UTF16 + X_UTF16)] // break out of 2x 2-byte seq loop due to ASCII data in first char of DWORD
- [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + EURO_SYMBOL_UTF16)] // break out of 2x 2-byte seq loop due to 3-byte data
- [InlineData(E_ACUTE_UTF16 + EURO_SYMBOL_UTF16)] // 2-byte logic sees next char isn't ASCII, cannot read full DWORD from remaining input buffer, falls down to slow drain loop
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + X_UTF16)] // 2x 3-byte logic can't read a full DWORD from next part of buffer, falls down to slow drain loop
- [InlineData(EURO_SYMBOL_UTF16 + X_UTF16)] // 3-byte processing loop consumes trailing ASCII char, but can't read next DWORD, falls down to slow drain loop
- [InlineData(EURO_SYMBOL_UTF16 + X_UTF16 + X_UTF16)] // 3-byte processing loop consumes trailing ASCII char, but can't read next DWORD, falls down to slow drain loop
- [InlineData(EURO_SYMBOL_UTF16 + E_ACUTE_UTF16)] // 3-byte processing loop can't consume next ASCII char, can't read DWORD, falls down to slow drain loop
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // stay within 2x 3-byte sequence processing loop
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + X_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // consume stray ASCII char at beginning of DWORD after 2x 3-byte sequence
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + X_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // consume stray ASCII char at end of DWORD after 2x 3-byte sequence
- [InlineData(EURO_SYMBOL_UTF16 + E_ACUTE_UTF16 + X_UTF16)] // consume 2-byte sequence as second char in DWORD which begins with 3-byte encoded char
- [InlineData(EURO_SYMBOL_UTF16 + GRINNING_FACE_UTF16)] // 3-byte sequence followed by 4-byte sequence
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + GRINNING_FACE_UTF16)] // 2x 3-byte sequence followed by 4-byte sequence
- [InlineData(GRINNING_FACE_UTF16)] // single 4-byte surrogate char pair
- [InlineData(GRINNING_FACE_UTF16 + EURO_SYMBOL_UTF16)] // 4-byte surrogate char pair, cannot read next DWORD, falls down to slow drain loop
- public void ToBytes_WithLargeValidBuffers(string utf16Input)
- {
- // These test cases are for the "fast processing" code which is the main loop of TranscodeToUtf8,
- // so inputs should be at least 2 chars.
-
- Assert.True(utf16Input.Length >= 2);
-
- // We're going to run the tests with destination buffer lengths ranging from 0 all the way
- // to buffers large enough to hold the full output. This allows us to test logic that
- // detects whether we're about to overrun our destination buffer and instead returns DestinationTooSmall.
-
- Rune[] enumeratedScalars = utf16Input.EnumerateRunes().ToArray();
-
- // 0-length buffer test
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: 0,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.DestinationTooSmall,
- expectedNumCharsRead: 0,
- expectedUtf8Transcoding: ReadOnlySpan<byte>.Empty);
-
- int expectedNumCharsConsumed = 0;
- byte[] concatenatedUtf8 = Array.Empty<byte>();
-
- for (int i = 0; i < enumeratedScalars.Length; i++)
- {
- Rune thisScalar = enumeratedScalars[i];
-
- // provide partial destination buffers all the way up to (but not including) enough to hold the next full scalar encoding
- for (int j = 1; j < thisScalar.Utf8SequenceLength; j++)
- {
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: concatenatedUtf8.Length + j,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.DestinationTooSmall,
- expectedNumCharsRead: expectedNumCharsConsumed,
- expectedUtf8Transcoding: concatenatedUtf8);
- }
-
- // now provide a destination buffer large enough to hold the next full scalar encoding
-
- expectedNumCharsConsumed += thisScalar.Utf16SequenceLength;
- concatenatedUtf8 = concatenatedUtf8.Concat(ToUtf8(thisScalar)).ToArray();
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: concatenatedUtf8.Length,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: (i == enumeratedScalars.Length - 1) ? OperationStatus.Done : OperationStatus.DestinationTooSmall,
- expectedNumCharsRead: expectedNumCharsConsumed,
- expectedUtf8Transcoding: concatenatedUtf8);
- }
-
- // now throw lots of ASCII data at the beginning so that we exercise the vectorized code paths
-
- utf16Input = new string('x', 64) + utf16Input;
- concatenatedUtf8 = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: concatenatedUtf8.Length,
- replaceInvalidSequences: false,
- isFinalChunk: true,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumCharsRead: utf16Input.Length,
- expectedUtf8Transcoding: concatenatedUtf8);
-
- // now throw some non-ASCII data at the beginning so that we *don't* exercise the vectorized code paths
-
- utf16Input = WOMAN_CARTWHEELING_MEDSKIN_UTF16 + utf16Input[64..];
- concatenatedUtf8 = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: concatenatedUtf8.Length,
- replaceInvalidSequences: false,
- isFinalChunk: true,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumCharsRead: utf16Input.Length,
- expectedUtf8Transcoding: concatenatedUtf8);
- }
-
- [Theory]
- [InlineData('\uD800', OperationStatus.NeedMoreData)] // standalone high surrogate
- [InlineData('\uDFFF', OperationStatus.InvalidData)] // standalone low surrogate
- public void ToBytes_WithOnlyStandaloneSurrogates(char charValue, OperationStatus expectedOperationStatus)
- {
- ToBytes_Test_Core(
- utf16Input: new[] { charValue },
- destinationSize: 0,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: expectedOperationStatus,
- expectedNumCharsRead: 0,
- expectedUtf8Transcoding: Span<byte>.Empty);
- }
-
- [Theory]
- [InlineData("<LOW><HIGH>", 0, "")] // swapped surrogate pair characters
- [InlineData("A<LOW><HIGH>", 1, "41")] // consume standalone ASCII char, then swapped surrogate pair characters
- [InlineData("A<HIGH>B", 1, "41")] // consume standalone ASCII char, then standalone high surrogate char
- [InlineData("A<LOW>B", 1, "41")] // consume standalone ASCII char, then standalone low surrogate char
- [InlineData("AB<HIGH><HIGH>", 2, "4142")] // consume two ASCII chars, then standalone high surrogate char
- [InlineData("AB<LOW><LOW>", 2, "4142")] // consume two ASCII chars, then standalone low surrogate char
- public void ToBytes_WithInvalidSurrogates(string utf16Input, int expectedNumCharsConsumed, string expectedUtf8TranscodingHex)
- {
- // xUnit can't handle ill-formed strings in [InlineData], so we replace here.
-
- utf16Input = utf16Input.Replace("<HIGH>", "\uD800").Replace("<LOW>", "\uDFFF");
-
- // These test cases are for the "fast processing" code which is the main loop of TranscodeToUtf8,
- // so inputs should be at least 2 chars.
-
- Assert.True(utf16Input.Length >= 2);
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: expectedUtf8TranscodingHex.Length / 2,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.InvalidData,
- expectedNumCharsRead: expectedNumCharsConsumed,
- expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
-
- // Now try the tests again with a larger buffer.
- // This ensures that running out of destination space wasn't the reason we failed.
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: (expectedUtf8TranscodingHex.Length) / 2 + 16,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.InvalidData,
- expectedNumCharsRead: expectedNumCharsConsumed,
- expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
- }
-
- [Theory]
- [InlineData("<LOW><HIGH>", REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete high surr.
- [InlineData("<HIGH><HIGH>", REPLACEMENT_CHAR_UTF8)] // standalone high surr. and incomplete high surr.
- [InlineData("<LOW><LOW>", REPLACEMENT_CHAR_UTF8 + REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete low surr.
- [InlineData("A<LOW>B<LOW>C<HIGH>D", "41" + REPLACEMENT_CHAR_UTF8 + "42" + REPLACEMENT_CHAR_UTF8 + "43" + REPLACEMENT_CHAR_UTF8 + "44")] // standalone low, low, high surrounded by other data
- public void ToBytes_WithReplacements(string utf16Input, string expectedUtf8TranscodingHex)
- {
- // xUnit can't handle ill-formed strings in [InlineData], so we replace here.
-
- utf16Input = utf16Input.Replace("<HIGH>", "\uD800").Replace("<LOW>", "\uDFFF");
-
- bool isFinalCharHighSurrogate = char.IsHighSurrogate(utf16Input.Last());
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: expectedUtf8TranscodingHex.Length / 2,
- replaceInvalidSequences: true,
- isFinalChunk: false,
- expectedOperationStatus: (isFinalCharHighSurrogate) ? OperationStatus.NeedMoreData : OperationStatus.Done,
- expectedNumCharsRead: (isFinalCharHighSurrogate) ? (utf16Input.Length - 1) : utf16Input.Length,
- expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
-
- if (isFinalCharHighSurrogate)
- {
- // Also test with isFinalChunk = true
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: expectedUtf8TranscodingHex.Length / 2 + Rune.ReplacementChar.Utf8SequenceLength /* for replacement char */,
- replaceInvalidSequences: true,
- isFinalChunk: true,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumCharsRead: utf16Input.Length,
- expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex + REPLACEMENT_CHAR_UTF8));
- }
- }
-
- [Theory]
- [InlineData(E_ACUTE_UTF16 + "<LOW>", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD
- [InlineData(E_ACUTE_UTF16 + "<LOW>", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone low surr. at end
- [InlineData(E_ACUTE_UTF16 + "<HIGH>", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD
- [InlineData(E_ACUTE_UTF16 + "<HIGH>", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone high surr. at end
- [InlineData(E_ACUTE_UTF16 + "<HIGH>", false, 1, OperationStatus.NeedMoreData, E_ACUTE_UTF8)] // don't replace standalone high surr. at end
- [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, true, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X'
- [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, false, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X'
- [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, true, 3, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8 + X_UTF8)] // replacement followed by 'X'
- [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, false, 3, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8 + X_UTF8)] // replacement followed by 'X'
- public void ToBytes_WithReplacements_AndCustomBufferSizes(string utf16Input, bool isFinalChunk, int expectedNumCharsConsumed, OperationStatus expectedOperationStatus, string expectedUtf8TranscodingHex)
- {
- // xUnit can't handle ill-formed strings in [InlineData], so we replace here.
-
- utf16Input = utf16Input.Replace("<HIGH>", "\uD800").Replace("<LOW>", "\uDFFF");
-
- ToBytes_Test_Core(
- utf16Input: utf16Input,
- destinationSize: expectedUtf8TranscodingHex.Length / 2,
- replaceInvalidSequences: true,
- isFinalChunk: isFinalChunk,
- expectedOperationStatus: expectedOperationStatus,
- expectedNumCharsRead: expectedNumCharsConsumed,
- expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
- }
-
- [Fact]
- public void ToBytes_AllPossibleScalarValues()
- {
- ToBytes_Test_Core(
- utf16Input: s_allScalarsAsUtf16.Span,
- destinationSize: s_allScalarsAsUtf8.Length,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumCharsRead: s_allScalarsAsUtf16.Length,
- expectedUtf8Transcoding: s_allScalarsAsUtf8.Span);
- }
-
- private static void ToBytes_Test_Core(ReadOnlySpan<char> utf16Input, int destinationSize, bool replaceInvalidSequences, bool isFinalChunk, OperationStatus expectedOperationStatus, int expectedNumCharsRead, ReadOnlySpan<byte> expectedUtf8Transcoding)
- {
- // Arrange
-
- using (BoundedMemory<char> boundedSource = BoundedMemory.AllocateFromExistingData(utf16Input))
- using (BoundedMemory<byte> boundedDestination = BoundedMemory.Allocate<byte>(destinationSize))
- {
- boundedSource.MakeReadonly();
-
- // Act
-
- OperationStatus actualOperationStatus = Utf8.FromUtf16(boundedSource.Span, boundedDestination.Span, out int actualNumCharsRead, out int actualNumBytesWritten, replaceInvalidSequences, isFinalChunk);
-
- // Assert
-
- Assert.Equal(expectedOperationStatus, actualOperationStatus);
- Assert.Equal(expectedNumCharsRead, actualNumCharsRead);
- Assert.Equal(expectedUtf8Transcoding.Length, actualNumBytesWritten);
- Assert.Equal(expectedUtf8Transcoding.ToArray(), boundedDestination.Span.Slice(0, actualNumBytesWritten).ToArray());
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Linq;
-using Xunit;
-
-namespace System.Text.Unicode.Tests
-{
- public partial class Utf8Tests
- {
- [Theory]
- [InlineData("80", 0, "")] // sequence cannot begin with continuation character
- [InlineData("8182", 0, "")] // sequence cannot begin with continuation character
- [InlineData("838485", 0, "")] // sequence cannot begin with continuation character
- [InlineData(X_UTF8 + "80", 1, X_UTF16)] // sequence cannot begin with continuation character
- [InlineData(X_UTF8 + "8182", 1, X_UTF16)] // sequence cannot begin with continuation character
- [InlineData("C0", 0, "")] // [ C0 ] is always invalid
- [InlineData("C080", 0, "")] // [ C0 ] is always invalid
- [InlineData("C08081", 0, "")] // [ C0 ] is always invalid
- [InlineData(X_UTF8 + "C1", 1, X_UTF16)] // [ C1 ] is always invalid
- [InlineData(X_UTF8 + "C180", 1, X_UTF16)] // [ C1 ] is always invalid
- [InlineData(X_UTF8 + "C27F", 1, X_UTF16)] // [ C2 ] is improperly terminated
- [InlineData("E2827F", 0, "")] // [ E2 82 ] is improperly terminated
- [InlineData("E09F80", 0, "")] // [ E0 9F ... ] is overlong
- [InlineData("E0C080", 0, "")] // [ E0 ] is improperly terminated
- [InlineData("ED7F80", 0, "")] // [ ED ] is improperly terminated
- [InlineData("EDA080", 0, "")] // [ ED A0 ... ] is surrogate
- public void ToChars_WithSmallInvalidBuffers(string utf8HexInput, int expectedNumBytesConsumed, string expectedUtf16Transcoding)
- {
- // These test cases are for the "slow processing" code path at the end of TranscodeToUtf16,
- // so inputs should be less than 4 bytes.
-
- Assert.InRange(utf8HexInput.Length, 0, 6);
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput),
- destinationSize: expectedUtf16Transcoding.Length,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.InvalidData,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
-
- // Now try the tests again with a larger buffer.
- // This ensures that running out of destination space wasn't the reason we failed.
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput),
- destinationSize: expectedUtf16Transcoding.Length + 16,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.InvalidData,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
- }
-
- [Theory]
- [InlineData("C2", 0, "")] // [ C2 ] is an incomplete sequence
- [InlineData("E282", 0, "")] // [ E2 82 ] is an incomplete sequence
- [InlineData(X_UTF8 + "C2", 1, X_UTF16)] // [ C2 ] is an incomplete sequence
- [InlineData(X_UTF8 + "E0", 1, X_UTF16)] // [ E0 ] is an incomplete sequence
- [InlineData(X_UTF8 + "E0BF", 1, X_UTF16)] // [ E0 BF ] is an incomplete sequence
- [InlineData(X_UTF8 + "F0", 1, X_UTF16)] // [ F0 ] is an incomplete sequence
- [InlineData(X_UTF8 + "F0BF", 1, X_UTF16)] // [ F0 BF ] is an incomplete sequence
- [InlineData(X_UTF8 + "F0BFA0", 1, X_UTF16)] // [ F0 BF A0 ] is an incomplete sequence
- [InlineData(E_ACUTE_UTF8 + "C2", 2, E_ACUTE_UTF16)] // [ C2 ] is an incomplete sequence
- [InlineData(E_ACUTE_UTF8 + "E0", 2, E_ACUTE_UTF16)] // [ E0 ] is an incomplete sequence
- [InlineData(E_ACUTE_UTF8 + "F0", 2, E_ACUTE_UTF16)] // [ F0 ] is an incomplete sequence
- [InlineData(E_ACUTE_UTF8 + "E0BF", 2, E_ACUTE_UTF16)] // [ E0 BF ] is an incomplete sequence
- [InlineData(E_ACUTE_UTF8 + "F0BF", 2, E_ACUTE_UTF16)] // [ F0 BF ] is an incomplete sequence
- [InlineData(EURO_SYMBOL_UTF8 + "C2", 3, EURO_SYMBOL_UTF16)] // [ C2 ] is an incomplete sequence
- [InlineData(EURO_SYMBOL_UTF8 + "E0", 3, EURO_SYMBOL_UTF16)] // [ E0 ] is an incomplete sequence
- [InlineData(EURO_SYMBOL_UTF8 + "F0", 3, EURO_SYMBOL_UTF16)] // [ F0 ] is an incomplete sequence
- public void ToChars_WithVariousIncompleteBuffers(string utf8HexInput, int expectedNumBytesConsumed, string expectedUtf16Transcoding)
- {
- // These test cases are for the "slow processing" code path at the end of TranscodeToUtf16,
- // so inputs should be less than 4 bytes.
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput),
- destinationSize: expectedUtf16Transcoding.Length,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.NeedMoreData,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
-
- // Now try the tests again with a larger buffer.
- // This ensures that running out of destination space wasn't the reason we failed.
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput),
- destinationSize: expectedUtf16Transcoding.Length + 16,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.NeedMoreData,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
- }
-
- [Theory]
- /* SMALL VALID BUFFERS - tests drain loop at end of method */
- [InlineData("")] // empty string is OK
- [InlineData("X")]
- [InlineData("XY")]
- [InlineData("XYZ")]
- [InlineData(E_ACUTE_UTF16)]
- [InlineData(X_UTF16 + E_ACUTE_UTF16)]
- [InlineData(E_ACUTE_UTF16 + X_UTF16)]
- [InlineData(EURO_SYMBOL_UTF16)]
- /* LARGE VALID BUFFERS - test main loop at beginning of method */
- [InlineData(E_ACUTE_UTF16 + "ABCD" + "0123456789:;<=>?")] // Loop unrolling at end of buffer
- [InlineData(E_ACUTE_UTF16 + "ABCD" + "0123456789:;<=>?" + "01234567" + E_ACUTE_UTF16 + "89:;<=>?")] // Loop unrolling interrupted by non-ASCII
- [InlineData("ABC" + E_ACUTE_UTF16 + "0123")] // 3 ASCII bytes followed by non-ASCII
- [InlineData("AB" + E_ACUTE_UTF16 + "0123")] // 2 ASCII bytes followed by non-ASCII
- [InlineData("A" + E_ACUTE_UTF16 + "0123")] // 1 ASCII byte followed by non-ASCII
- [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // 4x 2-byte sequences, exercises optimization code path in 2-byte sequence processing
- [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + "PQ")] // 3x 2-byte sequences + 2 ASCII bytes, exercises optimization code path in 2-byte sequence processing
- [InlineData(E_ACUTE_UTF16 + "PQ")] // single 2-byte sequence + 2 trailing ASCII bytes, exercises draining logic in 2-byte sequence processing
- [InlineData(E_ACUTE_UTF16 + "P" + E_ACUTE_UTF16 + "0@P")] // single 2-byte sequences + 1 trailing ASCII byte + 2-byte sequence, exercises draining logic in 2-byte sequence processing
- [InlineData(EURO_SYMBOL_UTF16 + "@")] // single 3-byte sequence + 1 trailing ASCII byte, exercises draining logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL_UTF16 + "@P`")] // single 3-byte sequence + 3 trailing ASCII byte, exercises draining logic and "running out of data" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // 3x 3-byte sequences, exercises "stay within 3-byte loop" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // 4x 3-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + E_ACUTE_UTF16)] // 3x 3-byte sequences + single 2-byte sequence, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // 2x 3-byte sequences + 4x 2-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
- [InlineData(GRINNING_FACE_UTF16 + GRINNING_FACE_UTF16)] // 2x 4-byte sequences, exercises 4-byte sequence processing
- [InlineData(GRINNING_FACE_UTF16 + "@AB")] // single 4-byte sequence + 3 ASCII bytes, exercises 4-byte sequence processing and draining logic
- [InlineData(WOMAN_CARTWHEELING_MEDSKIN_UTF16)] // exercises switching between multiple sequence lengths
- public void ToChars_ValidBuffers(string utf16Input)
- {
- // We're going to run the tests with destination buffer lengths ranging from 0 all the way
- // to buffers large enough to hold the full output. This allows us to test logic that
- // detects whether we're about to overrun our destination buffer and instead returns DestinationTooSmall.
-
- Rune[] enumeratedScalars = utf16Input.EnumerateRunes().ToArray();
-
- // Convert entire input to UTF-8 using our unit test reference logic.
-
- byte[] utf8Input = enumeratedScalars.SelectMany(ToUtf8).ToArray();
-
- // 0-length buffer test
- ToChars_Test_Core(
- utf8Input: utf8Input,
- destinationSize: 0,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: (utf8Input.Length == 0) ? OperationStatus.Done : OperationStatus.DestinationTooSmall,
- expectedNumBytesRead: 0,
- expectedUtf16Transcoding: ReadOnlySpan<char>.Empty);
-
- int expectedNumBytesConsumed = 0;
- char[] concatenatedUtf16 = Array.Empty<char>();
-
- for (int i = 0; i < enumeratedScalars.Length; i++)
- {
- Rune thisScalar = enumeratedScalars[i];
-
- // if this is an astral scalar value, quickly test a buffer that's not large enough to contain the entire UTF-16 encoding
-
- if (!thisScalar.IsBmp)
- {
- ToChars_Test_Core(
- utf8Input: utf8Input,
- destinationSize: concatenatedUtf16.Length + 1,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.DestinationTooSmall,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: concatenatedUtf16);
- }
-
- // now provide a destination buffer large enough to hold the next full scalar encoding
-
- expectedNumBytesConsumed += thisScalar.Utf8SequenceLength;
- concatenatedUtf16 = concatenatedUtf16.Concat(ToUtf16(thisScalar)).ToArray();
-
- ToChars_Test_Core(
- utf8Input: utf8Input,
- destinationSize: concatenatedUtf16.Length,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: (i == enumeratedScalars.Length - 1) ? OperationStatus.Done : OperationStatus.DestinationTooSmall,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: concatenatedUtf16);
- }
-
- // now throw lots of ASCII data at the beginning so that we exercise the vectorized code paths
-
- utf16Input = new string('x', 64) + utf16Input;
- utf8Input = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
-
- ToChars_Test_Core(
- utf8Input: utf8Input,
- destinationSize: utf16Input.Length,
- replaceInvalidSequences: false,
- isFinalChunk: true,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumBytesRead: utf8Input.Length,
- expectedUtf16Transcoding: utf16Input);
-
- // now throw some non-ASCII data at the beginning so that we *don't* exercise the vectorized code paths
-
- utf16Input = WOMAN_CARTWHEELING_MEDSKIN_UTF16 + utf16Input[64..];
- utf8Input = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
-
- ToChars_Test_Core(
- utf8Input: utf8Input,
- destinationSize: utf16Input.Length,
- replaceInvalidSequences: false,
- isFinalChunk: true,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumBytesRead: utf8Input.Length,
- expectedUtf16Transcoding: utf16Input);
- }
-
- [Theory]
- [InlineData("3031" + "80" + "202122232425", 2, "01")] // Continuation character at start of sequence should match no bitmask
- [InlineData("3031" + "C080" + "2021222324", 2, "01")] // Overlong 2-byte sequence at start of DWORD
- [InlineData("3031" + "C180" + "2021222324", 2, "01")] // Overlong 2-byte sequence at start of DWORD
- [InlineData("C280" + "C180", 2, "\u0080")] // Overlong 2-byte sequence at end of DWORD
- [InlineData("C27F" + "C280", 0, "")] // Improperly terminated 2-byte sequence at start of DWORD
- [InlineData("C2C0" + "C280", 0, "")] // Improperly terminated 2-byte sequence at start of DWORD
- [InlineData("C280" + "C27F", 2, "\u0080")] // Improperly terminated 2-byte sequence at end of DWORD
- [InlineData("C280" + "C2C0", 2, "\u0080")] // Improperly terminated 2-byte sequence at end of DWORD
- [InlineData("C280" + "C280" + "80203040", 4, "\u0080\u0080")] // Continuation character at start of sequence, within "stay in 2-byte processing" optimization
- [InlineData("C280" + "C280" + "C180" + "C280", 4, "\u0080\u0080")] // Overlong 2-byte sequence at start of DWORD, within "stay in 2-byte processing" optimization
- [InlineData("C280" + "C280" + "C280" + "C180", 6, "\u0080\u0080\u0080")] // Overlong 2-byte sequence at end of DWORD, within "stay in 2-byte processing" optimization
- [InlineData("3031" + "E09F80" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Overlong 3-byte sequence at start of DWORD
- [InlineData("3031" + "E07F80" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "E0C080" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "E17F80" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "E1C080" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "EDA080" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Surrogate 3-byte sequence at start of DWORD
- [InlineData("3031" + "E69C88" + "E59B" + "E69C88", 5, "01\u6708")] // Incomplete 3-byte sequence surrounded by valid 3-byte sequences
- [InlineData("3031" + "F5808080", 2, "01")] // [ F5 ] is always invalid
- [InlineData("3031" + "F6808080", 2, "01")] // [ F6 ] is always invalid
- [InlineData("3031" + "F7808080", 2, "01")] // [ F7 ] is always invalid
- [InlineData("3031" + "F8808080", 2, "01")] // [ F8 ] is always invalid
- [InlineData("3031" + "F9808080", 2, "01")] // [ F9 ] is always invalid
- [InlineData("3031" + "FA808080", 2, "01")] // [ FA ] is always invalid
- [InlineData("3031" + "FB808080", 2, "01")] // [ FB ] is always invalid
- [InlineData("3031" + "FC808080", 2, "01")] // [ FC ] is always invalid
- [InlineData("3031" + "FD808080", 2, "01")] // [ FD ] is always invalid
- [InlineData("3031" + "FE808080", 2, "01")] // [ FE ] is always invalid
- [InlineData("3031" + "FF808080", 2, "01")] // [ FF ] is always invalid
- public void ToChars_WithLargeInvalidBuffers(string utf8HexInput, int expectedNumBytesConsumed, string expectedUtf16Transcoding)
- {
- // These test cases are for the "fast processing" code which is the main loop of TranscodeToUtf16,
- // so inputs should be less >= 4 bytes.
-
- Assert.True(utf8HexInput.Length >= 8);
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput),
- destinationSize: expectedUtf16Transcoding.Length,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.InvalidData,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
-
- // Now try the tests again with a larger buffer.
- // This ensures that running out of destination space wasn't the reason we failed.
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput),
- destinationSize: expectedUtf16Transcoding.Length + 16,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.InvalidData,
- expectedNumBytesRead: expectedNumBytesConsumed,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
- }
-
- [Theory]
- [InlineData(X_UTF8 + "80" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // stray continuation byte [ 80 ]
- [InlineData(X_UTF8 + "FF" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // invalid UTF-8 byte [ FF ]
- [InlineData(X_UTF8 + "C2" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // 2-byte sequence starter [ C2 ] not followed by continuation byte
- [InlineData(X_UTF8 + "C1C180" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ C1 80 ] is overlong but consists of two maximal invalid subsequences, each of length 1 byte
- [InlineData(X_UTF8 + E_ACUTE_UTF8 + "E08080", X_UTF16 + E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16)] // [ E0 80 ] is overlong 2-byte sequence (1 byte maximal invalid subsequence), and following [ 80 ] is stray continuation byte
- [InlineData(GRINNING_FACE_UTF8 + "F08F8080" + GRINNING_FACE_UTF8, GRINNING_FACE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + GRINNING_FACE_UTF16)] // [ F0 8F ] is overlong 4-byte sequence (1 byte maximal invalid subsequence), and following [ 80 ] instances are stray continuation bytes
- [InlineData(GRINNING_FACE_UTF8 + "F4908080" + GRINNING_FACE_UTF8, GRINNING_FACE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + GRINNING_FACE_UTF16)] // [ F4 90 ] is out-of-range 4-byte sequence (1 byte maximal invalid subsequence), and following [ 80 ] instances are stray continuation bytes
- [InlineData(E_ACUTE_UTF8 + "EDA0" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ ED A0 ] is encoding of UTF-16 surrogate code point, so consists of two maximal invalid subsequences, each of length 1 byte
- [InlineData(E_ACUTE_UTF8 + "ED80" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ ED 80 ] is incomplete 3-byte sequence, so is 2-byte maximal invalid subsequence
- [InlineData(E_ACUTE_UTF8 + "F380" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ F3 80 ] is incomplete 4-byte sequence, so is 2-byte maximal invalid subsequence
- [InlineData(E_ACUTE_UTF8 + "F38080" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ F3 80 80 ] is incomplete 4-byte sequence, so is 3-byte maximal invalid subsequence
- public void ToChars_WithReplacement(string utf8HexInput, string expectedUtf16Transcoding)
- {
- // First run the test with isFinalBlock = false,
- // both with and without some bytes of incomplete trailing data.
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput),
- destinationSize: expectedUtf16Transcoding.Length,
- replaceInvalidSequences: true,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumBytesRead: utf8HexInput.Length / 2,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput + "E0BF" /* trailing data */),
- destinationSize: expectedUtf16Transcoding.Length,
- replaceInvalidSequences: true,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.NeedMoreData,
- expectedNumBytesRead: utf8HexInput.Length / 2,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
-
- // Then run the test with isFinalBlock = true, with incomplete trailing data.
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput + "E0BF" /* trailing data */),
- destinationSize: expectedUtf16Transcoding.Length,
- replaceInvalidSequences: true,
- isFinalChunk: true,
- expectedOperationStatus: OperationStatus.DestinationTooSmall,
- expectedNumBytesRead: utf8HexInput.Length / 2,
- expectedUtf16Transcoding: expectedUtf16Transcoding);
-
- ToChars_Test_Core(
- utf8Input: DecodeHex(utf8HexInput + "E0BF" /* trailing data */),
- destinationSize: expectedUtf16Transcoding.Length + 1, // allow room for U+FFFD
- replaceInvalidSequences: true,
- isFinalChunk: true,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumBytesRead: utf8HexInput.Length / 2 + 2,
- expectedUtf16Transcoding: expectedUtf16Transcoding + REPLACEMENT_CHAR_UTF16);
- }
-
- [Fact]
- public void ToChars_AllPossibleScalarValues()
- {
- ToChars_Test_Core(
- utf8Input: s_allScalarsAsUtf8.Span,
- destinationSize: s_allScalarsAsUtf16.Length,
- replaceInvalidSequences: false,
- isFinalChunk: false,
- expectedOperationStatus: OperationStatus.Done,
- expectedNumBytesRead: s_allScalarsAsUtf8.Length,
- expectedUtf16Transcoding: s_allScalarsAsUtf16.Span);
- }
-
- private static void ToChars_Test_Core(ReadOnlySpan<byte> utf8Input, int destinationSize, bool replaceInvalidSequences, bool isFinalChunk, OperationStatus expectedOperationStatus, int expectedNumBytesRead, ReadOnlySpan<char> expectedUtf16Transcoding)
- {
- // Arrange
-
- using (BoundedMemory<byte> boundedSource = BoundedMemory.AllocateFromExistingData(utf8Input))
- using (BoundedMemory<char> boundedDestination = BoundedMemory.Allocate<char>(destinationSize))
- {
- boundedSource.MakeReadonly();
-
- // Act
-
- OperationStatus actualOperationStatus = Utf8.ToUtf16(boundedSource.Span, boundedDestination.Span, out int actualNumBytesRead, out int actualNumCharsWritten, replaceInvalidSequences, isFinalChunk);
-
- // Assert
-
- Assert.Equal(expectedOperationStatus, actualOperationStatus);
- Assert.Equal(expectedNumBytesRead, actualNumBytesRead);
- Assert.Equal(expectedUtf16Transcoding.Length, actualNumCharsWritten);
- Assert.Equal(expectedUtf16Transcoding.ToString(), boundedDestination.Span.Slice(0, actualNumCharsWritten).ToString());
- }
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Xunit;
+
+namespace System.Text.Unicode.Tests
+{
+ public class Utf8Tests
+ {
+ private const string X_UTF8 = "58"; // U+0058 LATIN CAPITAL LETTER X, 1 byte
+ private const string X_UTF16 = "X";
+
+ private const string Y_UTF8 = "59"; // U+0058 LATIN CAPITAL LETTER Y, 1 byte
+ private const string Y_UTF16 = "Y";
+
+ private const string Z_UTF8 = "5A"; // U+0058 LATIN CAPITAL LETTER Z, 1 byte
+ private const string Z_UTF16 = "Z";
+
+ private const string E_ACUTE_UTF8 = "C3A9"; // U+00E9 LATIN SMALL LETTER E WITH ACUTE, 2 bytes
+ private const string E_ACUTE_UTF16 = "\u00E9";
+
+ private const string EURO_SYMBOL_UTF8 = "E282AC"; // U+20AC EURO SIGN, 3 bytes
+ private const string EURO_SYMBOL_UTF16 = "\u20AC";
+
+ private const string REPLACEMENT_CHAR_UTF8 = "EFBFBD"; // U+FFFD REPLACEMENT CHAR, 3 bytes
+ private const string REPLACEMENT_CHAR_UTF16 = "\uFFFD";
+
+ private const string GRINNING_FACE_UTF8 = "F09F9880"; // U+1F600 GRINNING FACE, 4 bytes
+ private const string GRINNING_FACE_UTF16 = "\U0001F600";
+
+ private const string WOMAN_CARTWHEELING_MEDSKIN_UTF16 = "\U0001F938\U0001F3FD\u200D\u2640\uFE0F"; // U+1F938 U+1F3FD U+200D U+2640 U+FE0F WOMAN CARTWHEELING: MEDIUM SKIN TONE
+
+ // All valid scalars [ U+0000 .. U+D7FF ] and [ U+E000 .. U+10FFFF ].
+ private static readonly IEnumerable<Rune> s_allValidScalars = Enumerable.Range(0x0000, 0xD800).Concat(Enumerable.Range(0xE000, 0x110000 - 0xE000)).Select(value => new Rune(value));
+
+ private static readonly ReadOnlyMemory<char> s_allScalarsAsUtf16;
+ private static readonly ReadOnlyMemory<byte> s_allScalarsAsUtf8;
+
+ static Utf8Tests()
+ {
+ List<char> allScalarsAsUtf16 = new List<char>();
+ List<byte> allScalarsAsUtf8 = new List<byte>();
+
+ foreach (Rune rune in s_allValidScalars)
+ {
+ allScalarsAsUtf16.AddRange(ToUtf16(rune));
+ allScalarsAsUtf8.AddRange(ToUtf8(rune));
+ }
+
+ s_allScalarsAsUtf16 = allScalarsAsUtf16.ToArray().AsMemory();
+ s_allScalarsAsUtf8 = allScalarsAsUtf8.ToArray().AsMemory();
+ }
+
+ /*
+ * COMMON UTILITIES FOR UNIT TESTS
+ */
+
+ public static byte[] DecodeHex(ReadOnlySpan<char> inputHex)
+ {
+ Assert.True(Regex.IsMatch(inputHex.ToString(), "^([0-9a-fA-F]{2})*$"), "Input must be an even number of hex characters.");
+
+ byte[] retVal = new byte[inputHex.Length / 2];
+ for (int i = 0; i < retVal.Length; i++)
+ {
+ retVal[i] = byte.Parse(inputHex.Slice(i * 2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
+ }
+ return retVal;
+ }
+
+ // !! IMPORTANT !!
+ // Don't delete this implementation, as we use it as a reference to make sure the framework's
+ // transcoding logic is correct.
+ public static byte[] ToUtf8(Rune rune)
+ {
+ Assert.True(Rune.IsValid(rune.Value), $"Rune with value U+{(uint)rune.Value:X4} is not well-formed.");
+
+ if (rune.Value < 0x80)
+ {
+ return new[]
+ {
+ (byte)rune.Value
+ };
+ }
+ else if (rune.Value < 0x0800)
+ {
+ return new[]
+ {
+ (byte)((rune.Value >> 6) | 0xC0),
+ (byte)((rune.Value & 0x3F) | 0x80)
+ };
+ }
+ else if (rune.Value < 0x10000)
+ {
+ return new[]
+ {
+ (byte)((rune.Value >> 12) | 0xE0),
+ (byte)(((rune.Value >> 6) & 0x3F) | 0x80),
+ (byte)((rune.Value & 0x3F) | 0x80)
+ };
+ }
+ else
+ {
+ return new[]
+ {
+ (byte)((rune.Value >> 18) | 0xF0),
+ (byte)(((rune.Value >> 12) & 0x3F) | 0x80),
+ (byte)(((rune.Value >> 6) & 0x3F) | 0x80),
+ (byte)((rune.Value & 0x3F) | 0x80)
+ };
+ }
+ }
+
+ // !! IMPORTANT !!
+ // Don't delete this implementation, as we use it as a reference to make sure the framework's
+ // transcoding logic is correct.
+ private static char[] ToUtf16(Rune rune)
+ {
+ Assert.True(Rune.IsValid(rune.Value), $"Rune with value U+{(uint)rune.Value:X4} is not well-formed.");
+
+ if (rune.IsBmp)
+ {
+ return new[]
+ {
+ (char)rune.Value
+ };
+ }
+ else
+ {
+ return new[]
+ {
+ (char)((rune.Value >> 10) + 0xD800 - 0x40),
+ (char)((rune.Value & 0x03FF) + 0xDC00)
+ };
+ }
+ }
+
+ [Theory]
+ [InlineData("", "")] // empty string is OK
+ [InlineData(X_UTF16, X_UTF8)]
+ [InlineData(E_ACUTE_UTF16, E_ACUTE_UTF8)]
+ [InlineData(EURO_SYMBOL_UTF16, EURO_SYMBOL_UTF8)]
+ public void ToBytes_WithSmallValidBuffers(string utf16Input, string expectedUtf8TranscodingHex)
+ {
+ // These test cases are for the "slow processing" code path at the end of TranscodeToUtf8,
+ // so inputs should be less than 2 chars.
+
+ Assert.InRange(utf16Input.Length, 0, 1);
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: expectedUtf8TranscodingHex.Length / 2,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumCharsRead: utf16Input.Length,
+ expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
+ }
+
+ [Theory]
+ [InlineData("AB")] // 2 ASCII chars, hits fast inner loop
+ [InlineData("ABCD")] // 4 ASCII chars, hits fast inner loop
+ [InlineData("ABCDEF")] // 6 ASCII chars, hits fast inner loop
+ [InlineData("ABCDEFGH")] // 8 ASCII chars, hits fast inner loop
+ [InlineData("ABCDEFGHIJ")] // 10 ASCII chars, hits fast inner loop
+ [InlineData("ABCDEF" + E_ACUTE_UTF16 + "HIJ")] // interrupts inner loop due to non-ASCII char in first char of first DWORD
+ [InlineData("ABCDEFG" + EURO_SYMBOL_UTF16 + "IJ")] // interrupts inner loop due to non-ASCII char in second char of first DWORD
+ [InlineData("ABCDEFGH" + E_ACUTE_UTF16 + "J")] // interrupts inner loop due to non-ASCII char in first char of second DWORD
+ [InlineData("ABCDEFGHI" + EURO_SYMBOL_UTF16)] // interrupts inner loop due to non-ASCII char in second char of second DWORD
+ [InlineData(X_UTF16 + E_ACUTE_UTF16)] // drains first ASCII char then falls down to slow path
+ [InlineData(X_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // drains first ASCII char then consumes 2x 2-byte sequences at once
+ [InlineData(E_ACUTE_UTF16 + X_UTF16)] // no first ASCII char to drain, consumes 2-byte seq followed by ASCII char
+ [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // stay within 2x 2-byte sequence processing loop
+ [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + X_UTF16)] // break out of 2x 2-byte seq loop due to ASCII data in second char of DWORD
+ [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + X_UTF16 + X_UTF16)] // break out of 2x 2-byte seq loop due to ASCII data in first char of DWORD
+ [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + EURO_SYMBOL_UTF16)] // break out of 2x 2-byte seq loop due to 3-byte data
+ [InlineData(E_ACUTE_UTF16 + EURO_SYMBOL_UTF16)] // 2-byte logic sees next char isn't ASCII, cannot read full DWORD from remaining input buffer, falls down to slow drain loop
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + X_UTF16)] // 2x 3-byte logic can't read a full DWORD from next part of buffer, falls down to slow drain loop
+ [InlineData(EURO_SYMBOL_UTF16 + X_UTF16)] // 3-byte processing loop consumes trailing ASCII char, but can't read next DWORD, falls down to slow drain loop
+ [InlineData(EURO_SYMBOL_UTF16 + X_UTF16 + X_UTF16)] // 3-byte processing loop consumes trailing ASCII char, but can't read next DWORD, falls down to slow drain loop
+ [InlineData(EURO_SYMBOL_UTF16 + E_ACUTE_UTF16)] // 3-byte processing loop can't consume next ASCII char, can't read DWORD, falls down to slow drain loop
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // stay within 2x 3-byte sequence processing loop
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + X_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // consume stray ASCII char at beginning of DWORD after 2x 3-byte sequence
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + X_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // consume stray ASCII char at end of DWORD after 2x 3-byte sequence
+ [InlineData(EURO_SYMBOL_UTF16 + E_ACUTE_UTF16 + X_UTF16)] // consume 2-byte sequence as second char in DWORD which begins with 3-byte encoded char
+ [InlineData(EURO_SYMBOL_UTF16 + GRINNING_FACE_UTF16)] // 3-byte sequence followed by 4-byte sequence
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + GRINNING_FACE_UTF16)] // 2x 3-byte sequence followed by 4-byte sequence
+ [InlineData(GRINNING_FACE_UTF16)] // single 4-byte surrogate char pair
+ [InlineData(GRINNING_FACE_UTF16 + EURO_SYMBOL_UTF16)] // 4-byte surrogate char pair, cannot read next DWORD, falls down to slow drain loop
+ public void ToBytes_WithLargeValidBuffers(string utf16Input)
+ {
+ // These test cases are for the "fast processing" code which is the main loop of TranscodeToUtf8,
+ // so inputs should be at least 2 chars.
+
+ Assert.True(utf16Input.Length >= 2);
+
+ // We're going to run the tests with destination buffer lengths ranging from 0 all the way
+ // to buffers large enough to hold the full output. This allows us to test logic that
+ // detects whether we're about to overrun our destination buffer and instead returns DestinationTooSmall.
+
+ Rune[] enumeratedScalars = utf16Input.EnumerateRunes().ToArray();
+
+ // 0-length buffer test
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: 0,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.DestinationTooSmall,
+ expectedNumCharsRead: 0,
+ expectedUtf8Transcoding: ReadOnlySpan<byte>.Empty);
+
+ int expectedNumCharsConsumed = 0;
+ byte[] concatenatedUtf8 = Array.Empty<byte>();
+
+ for (int i = 0; i < enumeratedScalars.Length; i++)
+ {
+ Rune thisScalar = enumeratedScalars[i];
+
+ // provide partial destination buffers all the way up to (but not including) enough to hold the next full scalar encoding
+ for (int j = 1; j < thisScalar.Utf8SequenceLength; j++)
+ {
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: concatenatedUtf8.Length + j,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.DestinationTooSmall,
+ expectedNumCharsRead: expectedNumCharsConsumed,
+ expectedUtf8Transcoding: concatenatedUtf8);
+ }
+
+ // now provide a destination buffer large enough to hold the next full scalar encoding
+
+ expectedNumCharsConsumed += thisScalar.Utf16SequenceLength;
+ concatenatedUtf8 = concatenatedUtf8.Concat(ToUtf8(thisScalar)).ToArray();
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: concatenatedUtf8.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: (i == enumeratedScalars.Length - 1) ? OperationStatus.Done : OperationStatus.DestinationTooSmall,
+ expectedNumCharsRead: expectedNumCharsConsumed,
+ expectedUtf8Transcoding: concatenatedUtf8);
+ }
+
+ // now throw lots of ASCII data at the beginning so that we exercise the vectorized code paths
+
+ utf16Input = new string('x', 64) + utf16Input;
+ concatenatedUtf8 = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: concatenatedUtf8.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: true,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumCharsRead: utf16Input.Length,
+ expectedUtf8Transcoding: concatenatedUtf8);
+
+ // now throw some non-ASCII data at the beginning so that we *don't* exercise the vectorized code paths
+
+ utf16Input = WOMAN_CARTWHEELING_MEDSKIN_UTF16 + utf16Input[64..];
+ concatenatedUtf8 = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: concatenatedUtf8.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: true,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumCharsRead: utf16Input.Length,
+ expectedUtf8Transcoding: concatenatedUtf8);
+ }
+
+ [Theory]
+ [InlineData('\uD800', OperationStatus.NeedMoreData)] // standalone high surrogate
+ [InlineData('\uDFFF', OperationStatus.InvalidData)] // standalone low surrogate
+ public void ToBytes_WithOnlyStandaloneSurrogates(char charValue, OperationStatus expectedOperationStatus)
+ {
+ ToBytes_Test_Core(
+ utf16Input: new[] { charValue },
+ destinationSize: 0,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: expectedOperationStatus,
+ expectedNumCharsRead: 0,
+ expectedUtf8Transcoding: Span<byte>.Empty);
+ }
+
+ [Theory]
+ [InlineData("<LOW><HIGH>", 0, "")] // swapped surrogate pair characters
+ [InlineData("A<LOW><HIGH>", 1, "41")] // consume standalone ASCII char, then swapped surrogate pair characters
+ [InlineData("A<HIGH>B", 1, "41")] // consume standalone ASCII char, then standalone high surrogate char
+ [InlineData("A<LOW>B", 1, "41")] // consume standalone ASCII char, then standalone low surrogate char
+ [InlineData("AB<HIGH><HIGH>", 2, "4142")] // consume two ASCII chars, then standalone high surrogate char
+ [InlineData("AB<LOW><LOW>", 2, "4142")] // consume two ASCII chars, then standalone low surrogate char
+ public void ToBytes_WithInvalidSurrogates(string utf16Input, int expectedNumCharsConsumed, string expectedUtf8TranscodingHex)
+ {
+ // xUnit can't handle ill-formed strings in [InlineData], so we replace here.
+
+ utf16Input = utf16Input.Replace("<HIGH>", "\uD800").Replace("<LOW>", "\uDFFF");
+
+ // These test cases are for the "fast processing" code which is the main loop of TranscodeToUtf8,
+ // so inputs should be at least 2 chars.
+
+ Assert.True(utf16Input.Length >= 2);
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: expectedUtf8TranscodingHex.Length / 2,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.InvalidData,
+ expectedNumCharsRead: expectedNumCharsConsumed,
+ expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
+
+ // Now try the tests again with a larger buffer.
+ // This ensures that running out of destination space wasn't the reason we failed.
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: (expectedUtf8TranscodingHex.Length) / 2 + 16,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.InvalidData,
+ expectedNumCharsRead: expectedNumCharsConsumed,
+ expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
+ }
+
+ [Theory]
+ [InlineData("<LOW><HIGH>", REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete high surr.
+ [InlineData("<HIGH><HIGH>", REPLACEMENT_CHAR_UTF8)] // standalone high surr. and incomplete high surr.
+ [InlineData("<LOW><LOW>", REPLACEMENT_CHAR_UTF8 + REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete low surr.
+ [InlineData("A<LOW>B<LOW>C<HIGH>D", "41" + REPLACEMENT_CHAR_UTF8 + "42" + REPLACEMENT_CHAR_UTF8 + "43" + REPLACEMENT_CHAR_UTF8 + "44")] // standalone low, low, high surrounded by other data
+ public void ToBytes_WithReplacements(string utf16Input, string expectedUtf8TranscodingHex)
+ {
+ // xUnit can't handle ill-formed strings in [InlineData], so we replace here.
+
+ utf16Input = utf16Input.Replace("<HIGH>", "\uD800").Replace("<LOW>", "\uDFFF");
+
+ bool isFinalCharHighSurrogate = char.IsHighSurrogate(utf16Input.Last());
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: expectedUtf8TranscodingHex.Length / 2,
+ replaceInvalidSequences: true,
+ isFinalChunk: false,
+ expectedOperationStatus: (isFinalCharHighSurrogate) ? OperationStatus.NeedMoreData : OperationStatus.Done,
+ expectedNumCharsRead: (isFinalCharHighSurrogate) ? (utf16Input.Length - 1) : utf16Input.Length,
+ expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
+
+ if (isFinalCharHighSurrogate)
+ {
+ // Also test with isFinalChunk = true
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: expectedUtf8TranscodingHex.Length / 2 + Rune.ReplacementChar.Utf8SequenceLength /* for replacement char */,
+ replaceInvalidSequences: true,
+ isFinalChunk: true,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumCharsRead: utf16Input.Length,
+ expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex + REPLACEMENT_CHAR_UTF8));
+ }
+ }
+
+ [Theory]
+ [InlineData(E_ACUTE_UTF16 + "<LOW>", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD
+ [InlineData(E_ACUTE_UTF16 + "<LOW>", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone low surr. at end
+ [InlineData(E_ACUTE_UTF16 + "<HIGH>", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD
+ [InlineData(E_ACUTE_UTF16 + "<HIGH>", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone high surr. at end
+ [InlineData(E_ACUTE_UTF16 + "<HIGH>", false, 1, OperationStatus.NeedMoreData, E_ACUTE_UTF8)] // don't replace standalone high surr. at end
+ [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, true, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X'
+ [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, false, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X'
+ [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, true, 3, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8 + X_UTF8)] // replacement followed by 'X'
+ [InlineData(E_ACUTE_UTF16 + "<HIGH>" + X_UTF16, false, 3, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8 + X_UTF8)] // replacement followed by 'X'
+ public void ToBytes_WithReplacements_AndCustomBufferSizes(string utf16Input, bool isFinalChunk, int expectedNumCharsConsumed, OperationStatus expectedOperationStatus, string expectedUtf8TranscodingHex)
+ {
+ // xUnit can't handle ill-formed strings in [InlineData], so we replace here.
+
+ utf16Input = utf16Input.Replace("<HIGH>", "\uD800").Replace("<LOW>", "\uDFFF");
+
+ ToBytes_Test_Core(
+ utf16Input: utf16Input,
+ destinationSize: expectedUtf8TranscodingHex.Length / 2,
+ replaceInvalidSequences: true,
+ isFinalChunk: isFinalChunk,
+ expectedOperationStatus: expectedOperationStatus,
+ expectedNumCharsRead: expectedNumCharsConsumed,
+ expectedUtf8Transcoding: DecodeHex(expectedUtf8TranscodingHex));
+ }
+
+ [Fact]
+ public void ToBytes_AllPossibleScalarValues()
+ {
+ ToBytes_Test_Core(
+ utf16Input: s_allScalarsAsUtf16.Span,
+ destinationSize: s_allScalarsAsUtf8.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumCharsRead: s_allScalarsAsUtf16.Length,
+ expectedUtf8Transcoding: s_allScalarsAsUtf8.Span);
+ }
+
+ private static void ToBytes_Test_Core(ReadOnlySpan<char> utf16Input, int destinationSize, bool replaceInvalidSequences, bool isFinalChunk, OperationStatus expectedOperationStatus, int expectedNumCharsRead, ReadOnlySpan<byte> expectedUtf8Transcoding)
+ {
+ // Arrange
+
+ using (BoundedMemory<char> boundedSource = BoundedMemory.AllocateFromExistingData(utf16Input))
+ using (BoundedMemory<byte> boundedDestination = BoundedMemory.Allocate<byte>(destinationSize))
+ {
+ boundedSource.MakeReadonly();
+
+ // Act
+
+ OperationStatus actualOperationStatus = Utf8.FromUtf16(boundedSource.Span, boundedDestination.Span, out int actualNumCharsRead, out int actualNumBytesWritten, replaceInvalidSequences, isFinalChunk);
+
+ // Assert
+
+ Assert.Equal(expectedOperationStatus, actualOperationStatus);
+ Assert.Equal(expectedNumCharsRead, actualNumCharsRead);
+ Assert.Equal(expectedUtf8Transcoding.Length, actualNumBytesWritten);
+ Assert.Equal(expectedUtf8Transcoding.ToArray(), boundedDestination.Span.Slice(0, actualNumBytesWritten).ToArray());
+ }
+ }
+
+ [Theory]
+ [InlineData("80", 0, "")] // sequence cannot begin with continuation character
+ [InlineData("8182", 0, "")] // sequence cannot begin with continuation character
+ [InlineData("838485", 0, "")] // sequence cannot begin with continuation character
+ [InlineData(X_UTF8 + "80", 1, X_UTF16)] // sequence cannot begin with continuation character
+ [InlineData(X_UTF8 + "8182", 1, X_UTF16)] // sequence cannot begin with continuation character
+ [InlineData("C0", 0, "")] // [ C0 ] is always invalid
+ [InlineData("C080", 0, "")] // [ C0 ] is always invalid
+ [InlineData("C08081", 0, "")] // [ C0 ] is always invalid
+ [InlineData(X_UTF8 + "C1", 1, X_UTF16)] // [ C1 ] is always invalid
+ [InlineData(X_UTF8 + "C180", 1, X_UTF16)] // [ C1 ] is always invalid
+ [InlineData(X_UTF8 + "C27F", 1, X_UTF16)] // [ C2 ] is improperly terminated
+ [InlineData("E2827F", 0, "")] // [ E2 82 ] is improperly terminated
+ [InlineData("E09F80", 0, "")] // [ E0 9F ... ] is overlong
+ [InlineData("E0C080", 0, "")] // [ E0 ] is improperly terminated
+ [InlineData("ED7F80", 0, "")] // [ ED ] is improperly terminated
+ [InlineData("EDA080", 0, "")] // [ ED A0 ... ] is surrogate
+ public void ToChars_WithSmallInvalidBuffers(string utf8HexInput, int expectedNumBytesConsumed, string expectedUtf16Transcoding)
+ {
+ // These test cases are for the "slow processing" code path at the end of TranscodeToUtf16,
+ // so inputs should be less than 4 bytes.
+
+ Assert.InRange(utf8HexInput.Length, 0, 6);
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput),
+ destinationSize: expectedUtf16Transcoding.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.InvalidData,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+
+ // Now try the tests again with a larger buffer.
+ // This ensures that running out of destination space wasn't the reason we failed.
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput),
+ destinationSize: expectedUtf16Transcoding.Length + 16,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.InvalidData,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+ }
+
+ [Theory]
+ [InlineData("C2", 0, "")] // [ C2 ] is an incomplete sequence
+ [InlineData("E282", 0, "")] // [ E2 82 ] is an incomplete sequence
+ [InlineData(X_UTF8 + "C2", 1, X_UTF16)] // [ C2 ] is an incomplete sequence
+ [InlineData(X_UTF8 + "E0", 1, X_UTF16)] // [ E0 ] is an incomplete sequence
+ [InlineData(X_UTF8 + "E0BF", 1, X_UTF16)] // [ E0 BF ] is an incomplete sequence
+ [InlineData(X_UTF8 + "F0", 1, X_UTF16)] // [ F0 ] is an incomplete sequence
+ [InlineData(X_UTF8 + "F0BF", 1, X_UTF16)] // [ F0 BF ] is an incomplete sequence
+ [InlineData(X_UTF8 + "F0BFA0", 1, X_UTF16)] // [ F0 BF A0 ] is an incomplete sequence
+ [InlineData(E_ACUTE_UTF8 + "C2", 2, E_ACUTE_UTF16)] // [ C2 ] is an incomplete sequence
+ [InlineData(E_ACUTE_UTF8 + "E0", 2, E_ACUTE_UTF16)] // [ E0 ] is an incomplete sequence
+ [InlineData(E_ACUTE_UTF8 + "F0", 2, E_ACUTE_UTF16)] // [ F0 ] is an incomplete sequence
+ [InlineData(E_ACUTE_UTF8 + "E0BF", 2, E_ACUTE_UTF16)] // [ E0 BF ] is an incomplete sequence
+ [InlineData(E_ACUTE_UTF8 + "F0BF", 2, E_ACUTE_UTF16)] // [ F0 BF ] is an incomplete sequence
+ [InlineData(EURO_SYMBOL_UTF8 + "C2", 3, EURO_SYMBOL_UTF16)] // [ C2 ] is an incomplete sequence
+ [InlineData(EURO_SYMBOL_UTF8 + "E0", 3, EURO_SYMBOL_UTF16)] // [ E0 ] is an incomplete sequence
+ [InlineData(EURO_SYMBOL_UTF8 + "F0", 3, EURO_SYMBOL_UTF16)] // [ F0 ] is an incomplete sequence
+ public void ToChars_WithVariousIncompleteBuffers(string utf8HexInput, int expectedNumBytesConsumed, string expectedUtf16Transcoding)
+ {
+ // These test cases are for the "slow processing" code path at the end of TranscodeToUtf16,
+ // so inputs should be less than 4 bytes.
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput),
+ destinationSize: expectedUtf16Transcoding.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.NeedMoreData,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+
+ // Now try the tests again with a larger buffer.
+ // This ensures that running out of destination space wasn't the reason we failed.
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput),
+ destinationSize: expectedUtf16Transcoding.Length + 16,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.NeedMoreData,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+ }
+
+ [Theory]
+ /* SMALL VALID BUFFERS - tests drain loop at end of method */
+ [InlineData("")] // empty string is OK
+ [InlineData("X")]
+ [InlineData("XY")]
+ [InlineData("XYZ")]
+ [InlineData(E_ACUTE_UTF16)]
+ [InlineData(X_UTF16 + E_ACUTE_UTF16)]
+ [InlineData(E_ACUTE_UTF16 + X_UTF16)]
+ [InlineData(EURO_SYMBOL_UTF16)]
+ /* LARGE VALID BUFFERS - test main loop at beginning of method */
+ [InlineData(E_ACUTE_UTF16 + "ABCD" + "0123456789:;<=>?")] // Loop unrolling at end of buffer
+ [InlineData(E_ACUTE_UTF16 + "ABCD" + "0123456789:;<=>?" + "01234567" + E_ACUTE_UTF16 + "89:;<=>?")] // Loop unrolling interrupted by non-ASCII
+ [InlineData("ABC" + E_ACUTE_UTF16 + "0123")] // 3 ASCII bytes followed by non-ASCII
+ [InlineData("AB" + E_ACUTE_UTF16 + "0123")] // 2 ASCII bytes followed by non-ASCII
+ [InlineData("A" + E_ACUTE_UTF16 + "0123")] // 1 ASCII byte followed by non-ASCII
+ [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // 4x 2-byte sequences, exercises optimization code path in 2-byte sequence processing
+ [InlineData(E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + "PQ")] // 3x 2-byte sequences + 2 ASCII bytes, exercises optimization code path in 2-byte sequence processing
+ [InlineData(E_ACUTE_UTF16 + "PQ")] // single 2-byte sequence + 2 trailing ASCII bytes, exercises draining logic in 2-byte sequence processing
+ [InlineData(E_ACUTE_UTF16 + "P" + E_ACUTE_UTF16 + "0@P")] // single 2-byte sequences + 1 trailing ASCII byte + 2-byte sequence, exercises draining logic in 2-byte sequence processing
+ [InlineData(EURO_SYMBOL_UTF16 + "@")] // single 3-byte sequence + 1 trailing ASCII byte, exercises draining logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL_UTF16 + "@P`")] // single 3-byte sequence + 3 trailing ASCII byte, exercises draining logic and "running out of data" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // 3x 3-byte sequences, exercises "stay within 3-byte loop" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16)] // 4x 3-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + E_ACUTE_UTF16)] // 3x 3-byte sequences + single 2-byte sequence, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL_UTF16 + EURO_SYMBOL_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16 + E_ACUTE_UTF16)] // 2x 3-byte sequences + 4x 2-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
+ [InlineData(GRINNING_FACE_UTF16 + GRINNING_FACE_UTF16)] // 2x 4-byte sequences, exercises 4-byte sequence processing
+ [InlineData(GRINNING_FACE_UTF16 + "@AB")] // single 4-byte sequence + 3 ASCII bytes, exercises 4-byte sequence processing and draining logic
+ [InlineData(WOMAN_CARTWHEELING_MEDSKIN_UTF16)] // exercises switching between multiple sequence lengths
+ public void ToChars_ValidBuffers(string utf16Input)
+ {
+ // We're going to run the tests with destination buffer lengths ranging from 0 all the way
+ // to buffers large enough to hold the full output. This allows us to test logic that
+ // detects whether we're about to overrun our destination buffer and instead returns DestinationTooSmall.
+
+ Rune[] enumeratedScalars = utf16Input.EnumerateRunes().ToArray();
+
+ // Convert entire input to UTF-8 using our unit test reference logic.
+
+ byte[] utf8Input = enumeratedScalars.SelectMany(ToUtf8).ToArray();
+
+ // 0-length buffer test
+ ToChars_Test_Core(
+ utf8Input: utf8Input,
+ destinationSize: 0,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: (utf8Input.Length == 0) ? OperationStatus.Done : OperationStatus.DestinationTooSmall,
+ expectedNumBytesRead: 0,
+ expectedUtf16Transcoding: ReadOnlySpan<char>.Empty);
+
+ int expectedNumBytesConsumed = 0;
+ char[] concatenatedUtf16 = Array.Empty<char>();
+
+ for (int i = 0; i < enumeratedScalars.Length; i++)
+ {
+ Rune thisScalar = enumeratedScalars[i];
+
+ // if this is an astral scalar value, quickly test a buffer that's not large enough to contain the entire UTF-16 encoding
+
+ if (!thisScalar.IsBmp)
+ {
+ ToChars_Test_Core(
+ utf8Input: utf8Input,
+ destinationSize: concatenatedUtf16.Length + 1,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.DestinationTooSmall,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: concatenatedUtf16);
+ }
+
+ // now provide a destination buffer large enough to hold the next full scalar encoding
+
+ expectedNumBytesConsumed += thisScalar.Utf8SequenceLength;
+ concatenatedUtf16 = concatenatedUtf16.Concat(ToUtf16(thisScalar)).ToArray();
+
+ ToChars_Test_Core(
+ utf8Input: utf8Input,
+ destinationSize: concatenatedUtf16.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: (i == enumeratedScalars.Length - 1) ? OperationStatus.Done : OperationStatus.DestinationTooSmall,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: concatenatedUtf16);
+ }
+
+ // now throw lots of ASCII data at the beginning so that we exercise the vectorized code paths
+
+ utf16Input = new string('x', 64) + utf16Input;
+ utf8Input = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
+
+ ToChars_Test_Core(
+ utf8Input: utf8Input,
+ destinationSize: utf16Input.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: true,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumBytesRead: utf8Input.Length,
+ expectedUtf16Transcoding: utf16Input);
+
+ // now throw some non-ASCII data at the beginning so that we *don't* exercise the vectorized code paths
+
+ utf16Input = WOMAN_CARTWHEELING_MEDSKIN_UTF16 + utf16Input[64..];
+ utf8Input = utf16Input.EnumerateRunes().SelectMany(ToUtf8).ToArray();
+
+ ToChars_Test_Core(
+ utf8Input: utf8Input,
+ destinationSize: utf16Input.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: true,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumBytesRead: utf8Input.Length,
+ expectedUtf16Transcoding: utf16Input);
+ }
+
+ [Theory]
+ [InlineData("3031" + "80" + "202122232425", 2, "01")] // Continuation character at start of sequence should match no bitmask
+ [InlineData("3031" + "C080" + "2021222324", 2, "01")] // Overlong 2-byte sequence at start of DWORD
+ [InlineData("3031" + "C180" + "2021222324", 2, "01")] // Overlong 2-byte sequence at start of DWORD
+ [InlineData("C280" + "C180", 2, "\u0080")] // Overlong 2-byte sequence at end of DWORD
+ [InlineData("C27F" + "C280", 0, "")] // Improperly terminated 2-byte sequence at start of DWORD
+ [InlineData("C2C0" + "C280", 0, "")] // Improperly terminated 2-byte sequence at start of DWORD
+ [InlineData("C280" + "C27F", 2, "\u0080")] // Improperly terminated 2-byte sequence at end of DWORD
+ [InlineData("C280" + "C2C0", 2, "\u0080")] // Improperly terminated 2-byte sequence at end of DWORD
+ [InlineData("C280" + "C280" + "80203040", 4, "\u0080\u0080")] // Continuation character at start of sequence, within "stay in 2-byte processing" optimization
+ [InlineData("C280" + "C280" + "C180" + "C280", 4, "\u0080\u0080")] // Overlong 2-byte sequence at start of DWORD, within "stay in 2-byte processing" optimization
+ [InlineData("C280" + "C280" + "C280" + "C180", 6, "\u0080\u0080\u0080")] // Overlong 2-byte sequence at end of DWORD, within "stay in 2-byte processing" optimization
+ [InlineData("3031" + "E09F80" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Overlong 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E07F80" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E0C080" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E17F80" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E1C080" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "EDA080" + EURO_SYMBOL_UTF8 + EURO_SYMBOL_UTF8, 2, "01")] // Surrogate 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E69C88" + "E59B" + "E69C88", 5, "01\u6708")] // Incomplete 3-byte sequence surrounded by valid 3-byte sequences
+ [InlineData("3031" + "F5808080", 2, "01")] // [ F5 ] is always invalid
+ [InlineData("3031" + "F6808080", 2, "01")] // [ F6 ] is always invalid
+ [InlineData("3031" + "F7808080", 2, "01")] // [ F7 ] is always invalid
+ [InlineData("3031" + "F8808080", 2, "01")] // [ F8 ] is always invalid
+ [InlineData("3031" + "F9808080", 2, "01")] // [ F9 ] is always invalid
+ [InlineData("3031" + "FA808080", 2, "01")] // [ FA ] is always invalid
+ [InlineData("3031" + "FB808080", 2, "01")] // [ FB ] is always invalid
+ [InlineData("3031" + "FC808080", 2, "01")] // [ FC ] is always invalid
+ [InlineData("3031" + "FD808080", 2, "01")] // [ FD ] is always invalid
+ [InlineData("3031" + "FE808080", 2, "01")] // [ FE ] is always invalid
+ [InlineData("3031" + "FF808080", 2, "01")] // [ FF ] is always invalid
+ public void ToChars_WithLargeInvalidBuffers(string utf8HexInput, int expectedNumBytesConsumed, string expectedUtf16Transcoding)
+ {
+ // These test cases are for the "fast processing" code which is the main loop of TranscodeToUtf16,
+ // so inputs should be less >= 4 bytes.
+
+ Assert.True(utf8HexInput.Length >= 8);
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput),
+ destinationSize: expectedUtf16Transcoding.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.InvalidData,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+
+ // Now try the tests again with a larger buffer.
+ // This ensures that running out of destination space wasn't the reason we failed.
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput),
+ destinationSize: expectedUtf16Transcoding.Length + 16,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.InvalidData,
+ expectedNumBytesRead: expectedNumBytesConsumed,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+ }
+
+ [Theory]
+ [InlineData(X_UTF8 + "80" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // stray continuation byte [ 80 ]
+ [InlineData(X_UTF8 + "FF" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // invalid UTF-8 byte [ FF ]
+ [InlineData(X_UTF8 + "C2" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // 2-byte sequence starter [ C2 ] not followed by continuation byte
+ [InlineData(X_UTF8 + "C1C180" + X_UTF8, X_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ C1 80 ] is overlong but consists of two maximal invalid subsequences, each of length 1 byte
+ [InlineData(X_UTF8 + E_ACUTE_UTF8 + "E08080", X_UTF16 + E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16)] // [ E0 80 ] is overlong 2-byte sequence (1 byte maximal invalid subsequence), and following [ 80 ] is stray continuation byte
+ [InlineData(GRINNING_FACE_UTF8 + "F08F8080" + GRINNING_FACE_UTF8, GRINNING_FACE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + GRINNING_FACE_UTF16)] // [ F0 8F ] is overlong 4-byte sequence (1 byte maximal invalid subsequence), and following [ 80 ] instances are stray continuation bytes
+ [InlineData(GRINNING_FACE_UTF8 + "F4908080" + GRINNING_FACE_UTF8, GRINNING_FACE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + GRINNING_FACE_UTF16)] // [ F4 90 ] is out-of-range 4-byte sequence (1 byte maximal invalid subsequence), and following [ 80 ] instances are stray continuation bytes
+ [InlineData(E_ACUTE_UTF8 + "EDA0" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ ED A0 ] is encoding of UTF-16 surrogate code point, so consists of two maximal invalid subsequences, each of length 1 byte
+ [InlineData(E_ACUTE_UTF8 + "ED80" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ ED 80 ] is incomplete 3-byte sequence, so is 2-byte maximal invalid subsequence
+ [InlineData(E_ACUTE_UTF8 + "F380" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ F3 80 ] is incomplete 4-byte sequence, so is 2-byte maximal invalid subsequence
+ [InlineData(E_ACUTE_UTF8 + "F38080" + X_UTF8, E_ACUTE_UTF16 + REPLACEMENT_CHAR_UTF16 + X_UTF16)] // [ F3 80 80 ] is incomplete 4-byte sequence, so is 3-byte maximal invalid subsequence
+ public void ToChars_WithReplacement(string utf8HexInput, string expectedUtf16Transcoding)
+ {
+ // First run the test with isFinalBlock = false,
+ // both with and without some bytes of incomplete trailing data.
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput),
+ destinationSize: expectedUtf16Transcoding.Length,
+ replaceInvalidSequences: true,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumBytesRead: utf8HexInput.Length / 2,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput + "E0BF" /* trailing data */),
+ destinationSize: expectedUtf16Transcoding.Length,
+ replaceInvalidSequences: true,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.NeedMoreData,
+ expectedNumBytesRead: utf8HexInput.Length / 2,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+
+ // Then run the test with isFinalBlock = true, with incomplete trailing data.
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput + "E0BF" /* trailing data */),
+ destinationSize: expectedUtf16Transcoding.Length,
+ replaceInvalidSequences: true,
+ isFinalChunk: true,
+ expectedOperationStatus: OperationStatus.DestinationTooSmall,
+ expectedNumBytesRead: utf8HexInput.Length / 2,
+ expectedUtf16Transcoding: expectedUtf16Transcoding);
+
+ ToChars_Test_Core(
+ utf8Input: DecodeHex(utf8HexInput + "E0BF" /* trailing data */),
+ destinationSize: expectedUtf16Transcoding.Length + 1, // allow room for U+FFFD
+ replaceInvalidSequences: true,
+ isFinalChunk: true,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumBytesRead: utf8HexInput.Length / 2 + 2,
+ expectedUtf16Transcoding: expectedUtf16Transcoding + REPLACEMENT_CHAR_UTF16);
+ }
+
+ [Fact]
+ public void ToChars_AllPossibleScalarValues()
+ {
+ ToChars_Test_Core(
+ utf8Input: s_allScalarsAsUtf8.Span,
+ destinationSize: s_allScalarsAsUtf16.Length,
+ replaceInvalidSequences: false,
+ isFinalChunk: false,
+ expectedOperationStatus: OperationStatus.Done,
+ expectedNumBytesRead: s_allScalarsAsUtf8.Length,
+ expectedUtf16Transcoding: s_allScalarsAsUtf16.Span);
+ }
+
+ private static void ToChars_Test_Core(ReadOnlySpan<byte> utf8Input, int destinationSize, bool replaceInvalidSequences, bool isFinalChunk, OperationStatus expectedOperationStatus, int expectedNumBytesRead, ReadOnlySpan<char> expectedUtf16Transcoding)
+ {
+ // Arrange
+
+ using (BoundedMemory<byte> boundedSource = BoundedMemory.AllocateFromExistingData(utf8Input))
+ using (BoundedMemory<char> boundedDestination = BoundedMemory.Allocate<char>(destinationSize))
+ {
+ boundedSource.MakeReadonly();
+
+ // Act
+
+ OperationStatus actualOperationStatus = Utf8.ToUtf16(boundedSource.Span, boundedDestination.Span, out int actualNumBytesRead, out int actualNumCharsWritten, replaceInvalidSequences, isFinalChunk);
+
+ // Assert
+
+ Assert.Equal(expectedOperationStatus, actualOperationStatus);
+ Assert.Equal(expectedNumBytesRead, actualNumBytesRead);
+ Assert.Equal(expectedUtf16Transcoding.Length, actualNumCharsWritten);
+ Assert.Equal(expectedUtf16Transcoding.ToString(), boundedDestination.Span.Slice(0, actualNumCharsWritten).ToString());
+ }
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text.RegularExpressions;
-using Xunit;
-
-namespace System.Text.Unicode.Tests
-{
- public partial class Utf8Tests
- {
- private const string X_UTF8 = "58"; // U+0058 LATIN CAPITAL LETTER X, 1 byte
- private const string X_UTF16 = "X";
-
- private const string Y_UTF8 = "59"; // U+0058 LATIN CAPITAL LETTER Y, 1 byte
- private const string Y_UTF16 = "Y";
-
- private const string Z_UTF8 = "5A"; // U+0058 LATIN CAPITAL LETTER Z, 1 byte
- private const string Z_UTF16 = "Z";
-
- private const string E_ACUTE_UTF8 = "C3A9"; // U+00E9 LATIN SMALL LETTER E WITH ACUTE, 2 bytes
- private const string E_ACUTE_UTF16 = "\u00E9";
-
- private const string EURO_SYMBOL_UTF8 = "E282AC"; // U+20AC EURO SIGN, 3 bytes
- private const string EURO_SYMBOL_UTF16 = "\u20AC";
-
- private const string REPLACEMENT_CHAR_UTF8 = "EFBFBD"; // U+FFFD REPLACEMENT CHAR, 3 bytes
- private const string REPLACEMENT_CHAR_UTF16 = "\uFFFD";
-
- private const string GRINNING_FACE_UTF8 = "F09F9880"; // U+1F600 GRINNING FACE, 4 bytes
- private const string GRINNING_FACE_UTF16 = "\U0001F600";
-
- private const string WOMAN_CARTWHEELING_MEDSKIN_UTF16 = "\U0001F938\U0001F3FD\u200D\u2640\uFE0F"; // U+1F938 U+1F3FD U+200D U+2640 U+FE0F WOMAN CARTWHEELING: MEDIUM SKIN TONE
-
- // All valid scalars [ U+0000 .. U+D7FF ] and [ U+E000 .. U+10FFFF ].
- private static readonly IEnumerable<Rune> s_allValidScalars = Enumerable.Range(0x0000, 0xD800).Concat(Enumerable.Range(0xE000, 0x110000 - 0xE000)).Select(value => new Rune(value));
-
- private static readonly ReadOnlyMemory<char> s_allScalarsAsUtf16;
- private static readonly ReadOnlyMemory<byte> s_allScalarsAsUtf8;
-
- static Utf8Tests()
- {
- List<char> allScalarsAsUtf16 = new List<char>();
- List<byte> allScalarsAsUtf8 = new List<byte>();
-
- foreach (Rune rune in s_allValidScalars)
- {
- allScalarsAsUtf16.AddRange(ToUtf16(rune));
- allScalarsAsUtf8.AddRange(ToUtf8(rune));
- }
-
- s_allScalarsAsUtf16 = allScalarsAsUtf16.ToArray().AsMemory();
- s_allScalarsAsUtf8 = allScalarsAsUtf8.ToArray().AsMemory();
- }
-
- /*
- * COMMON UTILITIES FOR UNIT TESTS
- */
-
- public static byte[] DecodeHex(ReadOnlySpan<char> inputHex)
- {
- Assert.True(Regex.IsMatch(inputHex.ToString(), "^([0-9a-fA-F]{2})*$"), "Input must be an even number of hex characters.");
-
- byte[] retVal = new byte[inputHex.Length / 2];
- for (int i = 0; i < retVal.Length; i++)
- {
- retVal[i] = byte.Parse(inputHex.Slice(i * 2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
- }
- return retVal;
- }
-
- // !! IMPORTANT !!
- // Don't delete this implementation, as we use it as a reference to make sure the framework's
- // transcoding logic is correct.
- public static byte[] ToUtf8(Rune rune)
- {
- Assert.True(Rune.IsValid(rune.Value), $"Rune with value U+{(uint)rune.Value:X4} is not well-formed.");
-
- if (rune.Value < 0x80)
- {
- return new[]
- {
- (byte)rune.Value
- };
- }
- else if (rune.Value < 0x0800)
- {
- return new[]
- {
- (byte)((rune.Value >> 6) | 0xC0),
- (byte)((rune.Value & 0x3F) | 0x80)
- };
- }
- else if (rune.Value < 0x10000)
- {
- return new[]
- {
- (byte)((rune.Value >> 12) | 0xE0),
- (byte)(((rune.Value >> 6) & 0x3F) | 0x80),
- (byte)((rune.Value & 0x3F) | 0x80)
- };
- }
- else
- {
- return new[]
- {
- (byte)((rune.Value >> 18) | 0xF0),
- (byte)(((rune.Value >> 12) & 0x3F) | 0x80),
- (byte)(((rune.Value >> 6) & 0x3F) | 0x80),
- (byte)((rune.Value & 0x3F) | 0x80)
- };
- }
- }
-
- // !! IMPORTANT !!
- // Don't delete this implementation, as we use it as a reference to make sure the framework's
- // transcoding logic is correct.
- private static char[] ToUtf16(Rune rune)
- {
- Assert.True(Rune.IsValid(rune.Value), $"Rune with value U+{(uint)rune.Value:X4} is not well-formed.");
-
- if (rune.IsBmp)
- {
- return new[]
- {
- (char)rune.Value
- };
- }
- else
- {
- return new[]
- {
- (char)((rune.Value >> 10) + 0xD800 - 0x40),
- (char)((rune.Value & 0x03FF) + 0xDC00)
- };
- }
- }
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.Text.Unicode.Tests
+{
+ public class Utf8UtilityTests
+ {
+ private unsafe delegate byte* GetPointerToFirstInvalidByteDel(byte* pInputBuffer, int inputLength, out int utf16CodeUnitCountAdjustment, out int scalarCountAdjustment);
+ private static readonly Lazy<GetPointerToFirstInvalidByteDel> _getPointerToFirstInvalidByteFn = CreateGetPointerToFirstInvalidByteFn();
+
+ private const string X = "58"; // U+0058 LATIN CAPITAL LETTER X, 1 byte
+ private const string Y = "59"; // U+0058 LATIN CAPITAL LETTER Y, 1 byte
+ private const string Z = "5A"; // U+0058 LATIN CAPITAL LETTER Z, 1 byte
+ private const string E_ACUTE = "C3A9"; // U+00E9 LATIN SMALL LETTER E WITH ACUTE, 2 bytes
+ private const string EURO_SYMBOL = "E282AC"; // U+20AC EURO SIGN, 3 bytes
+ private const string GRINNING_FACE = "F09F9880"; // U+1F600 GRINNING FACE, 4 bytes
+
+ [Theory]
+ [InlineData("", 0, 0)] // empty string is OK
+ [InlineData(X, 1, 0)]
+ [InlineData(X + Y, 2, 0)]
+ [InlineData(X + Y + Z, 3, 0)]
+ [InlineData(E_ACUTE, 1, 0)]
+ [InlineData(X + E_ACUTE, 2, 0)]
+ [InlineData(E_ACUTE + X, 2, 0)]
+ [InlineData(EURO_SYMBOL, 1, 0)]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithSmallValidBuffers(string input, int expectedRuneCount, int expectedSurrogatePairCount)
+ {
+ // These test cases are for the "slow processing" code path at the end of GetIndexOfFirstInvalidUtf8Sequence,
+ // so inputs should be less than 4 bytes.
+
+ Assert.InRange(input.Length, 0, 6);
+
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, -1 /* expectedRetVal */, expectedRuneCount, expectedSurrogatePairCount);
+ }
+
+ [Theory]
+ [InlineData("80", 0, 0, 0)] // sequence cannot begin with continuation character
+ [InlineData("8182", 0, 0, 0)] // sequence cannot begin with continuation character
+ [InlineData("838485", 0, 0, 0)] // sequence cannot begin with continuation character
+ [InlineData(X + "80", 1, 1, 0)] // sequence cannot begin with continuation character
+ [InlineData(X + "8182", 1, 1, 0)] // sequence cannot begin with continuation character
+ [InlineData("C0", 0, 0, 0)] // [ C0 ] is always invalid
+ [InlineData("C080", 0, 0, 0)] // [ C0 ] is always invalid
+ [InlineData("C08081", 0, 0, 0)] // [ C0 ] is always invalid
+ [InlineData(X + "C1", 1, 1, 0)] // [ C1 ] is always invalid
+ [InlineData(X + "C180", 1, 1, 0)] // [ C1 ] is always invalid
+ [InlineData("C2", 0, 0, 0)] // [ C2 ] is improperly terminated
+ [InlineData(X + "C27F", 1, 1, 0)] // [ C2 ] is improperly terminated
+ [InlineData(X + "E282", 1, 1, 0)] // [ E2 82 ] is improperly terminated
+ [InlineData("E2827F", 0, 0, 0)] // [ E2 82 ] is improperly terminated
+ [InlineData("E09F80", 0, 0, 0)] // [ E0 9F ... ] is overlong
+ [InlineData("E0C080", 0, 0, 0)] // [ E0 ] is improperly terminated
+ [InlineData("ED7F80", 0, 0, 0)] // [ ED ] is improperly terminated
+ [InlineData("EDA080", 0, 0, 0)] // [ ED A0 ... ] is surrogate
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithSmallInvalidBuffers(string input, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
+ {
+ // These test cases are for the "slow processing" code path at the end of GetIndexOfFirstInvalidUtf8Sequence,
+ // so inputs should be less than 4 bytes.
+
+ Assert.InRange(input.Length, 0, 6);
+
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, expectedRetVal, expectedRuneCount, expectedSurrogatePairCount);
+ }
+
+ [Theory]
+ [InlineData(E_ACUTE + "21222324" + "303132333435363738393A3B3C3D3E3F", 21, 0)] // Loop unrolling at end of buffer
+ [InlineData(E_ACUTE + "21222324" + "303132333435363738393A3B3C3D3E3F" + "3031323334353637" + E_ACUTE + "38393A3B3C3D3E3F", 38, 0)] // Loop unrolling interrupted by non-ASCII
+ [InlineData("212223" + E_ACUTE + "30313233", 8, 0)] // 3 ASCII bytes followed by non-ASCII
+ [InlineData("2122" + E_ACUTE + "30313233", 7, 0)] // 2 ASCII bytes followed by non-ASCII
+ [InlineData("21" + E_ACUTE + "30313233", 6, 0)] // 1 ASCII byte followed by non-ASCII
+ [InlineData(E_ACUTE + E_ACUTE + E_ACUTE + E_ACUTE, 4, 0)] // 4x 2-byte sequences, exercises optimization code path in 2-byte sequence processing
+ [InlineData(E_ACUTE + E_ACUTE + E_ACUTE + "5051", 5, 0)] // 3x 2-byte sequences + 2 ASCII bytes, exercises optimization code path in 2-byte sequence processing
+ [InlineData(E_ACUTE + "5051", 3, 0)] // single 2-byte sequence + 2 trailing ASCII bytes, exercises draining logic in 2-byte sequence processing
+ [InlineData(E_ACUTE + "50" + E_ACUTE + "304050", 6, 0)] // single 2-byte sequences + 1 trailing ASCII byte + 2-byte sequence, exercises draining logic in 2-byte sequence processing
+ [InlineData(EURO_SYMBOL + "20", 2, 0)] // single 3-byte sequence + 1 trailing ASCII byte, exercises draining logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL + "203040", 4, 0)] // single 3-byte sequence + 3 trailing ASCII byte, exercises draining logic and "running out of data" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL, 3, 0)] // 3x 3-byte sequences, exercises "stay within 3-byte loop" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL, 4, 0)] // 4x 3-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL + E_ACUTE, 4, 0)] // 3x 3-byte sequences + single 2-byte sequence, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
+ [InlineData(EURO_SYMBOL + EURO_SYMBOL + E_ACUTE + E_ACUTE + E_ACUTE + E_ACUTE, 6, 0)] // 2x 3-byte sequences + 4x 2-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
+ [InlineData(GRINNING_FACE + GRINNING_FACE, 2, 2)] // 2x 4-byte sequences, exercises 4-byte sequence processing
+ [InlineData(GRINNING_FACE + "303132", 4, 1)] // single 4-byte sequence + 3 ASCII bytes, exercises 4-byte sequence processing and draining logic
+ [InlineData("F09FA4B8" + "F09F8FBD" + "E2808D" + "E29980" + "EFB88F", 5, 2)] // U+1F938 U+1F3FD U+200D U+2640 U+FE0F WOMAN CARTWHEELING: MEDIUM SKIN TONE, exercising switching between multiple sequence lengths
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithLargeValidBuffers(string input, int expectedRuneCount, int expectedSurrogatePairCount)
+ {
+ // These test cases are for the "fast processing" code which is the main loop of GetIndexOfFirstInvalidUtf8Sequence,
+ // so inputs should be less >= 4 bytes.
+
+ Assert.True(input.Length >= 8);
+
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, -1 /* expectedRetVal */, expectedRuneCount, expectedSurrogatePairCount);
+ }
+
+ [Theory]
+ [InlineData("3031" + "80" + "202122232425", 2, 2, 0)] // Continuation character at start of sequence should match no bitmask
+ [InlineData("3031" + "C080" + "2021222324", 2, 2, 0)] // Overlong 2-byte sequence at start of DWORD
+ [InlineData("3031" + "C180" + "2021222324", 2, 2, 0)] // Overlong 2-byte sequence at start of DWORD
+ [InlineData("C280" + "C180", 2, 1, 0)] // Overlong 2-byte sequence at end of DWORD
+ [InlineData("C27F" + "C280", 0, 0, 0)] // Improperly terminated 2-byte sequence at start of DWORD
+ [InlineData("C2C0" + "C280", 0, 0, 0)] // Improperly terminated 2-byte sequence at start of DWORD
+ [InlineData("C280" + "C27F", 2, 1, 0)] // Improperly terminated 2-byte sequence at end of DWORD
+ [InlineData("C280" + "C2C0", 2, 1, 0)] // Improperly terminated 2-byte sequence at end of DWORD
+ [InlineData("C280" + "C280" + "80203040", 4, 2, 0)] // Continuation character at start of sequence, within "stay in 2-byte processing" optimization
+ [InlineData("C280" + "C280" + "C180" + "C280", 4, 2, 0)] // Overlong 2-byte sequence at start of DWORD, within "stay in 2-byte processing" optimization
+ [InlineData("C280" + "C280" + "C280" + "C180", 6, 3, 0)] // Overlong 2-byte sequence at end of DWORD, within "stay in 2-byte processing" optimization
+ [InlineData("3031" + "E09F80" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Overlong 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E07F80" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E0C080" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E17F80" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E1C080" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
+ [InlineData("3031" + "EDA080" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Surrogate 3-byte sequence at start of DWORD
+ [InlineData("3031" + "E69C88" + "E59B" + "E69C88", 5, 3, 0)] // Incomplete 3-byte sequence surrounded by valid 3-byte sequences
+ [InlineData("E78B80" + "80", 3, 1, 0)] // Valid 3-byte sequence followed by standalone continuation byte
+ [InlineData("3031" + "F5808080", 2, 2, 0)] // [ F5 ] is always invalid
+ [InlineData("3031" + "F6808080", 2, 2, 0)] // [ F6 ] is always invalid
+ [InlineData("3031" + "F7808080", 2, 2, 0)] // [ F7 ] is always invalid
+ [InlineData("3031" + "F8808080", 2, 2, 0)] // [ F8 ] is always invalid
+ [InlineData("3031" + "F9808080", 2, 2, 0)] // [ F9 ] is always invalid
+ [InlineData("3031" + "FA808080", 2, 2, 0)] // [ FA ] is always invalid
+ [InlineData("3031" + "FB808080", 2, 2, 0)] // [ FB ] is always invalid
+ [InlineData("3031" + "FC808080", 2, 2, 0)] // [ FC ] is always invalid
+ [InlineData("3031" + "FD808080", 2, 2, 0)] // [ FD ] is always invalid
+ [InlineData("3031" + "FE808080", 2, 2, 0)] // [ FE ] is always invalid
+ [InlineData("3031" + "FF808080", 2, 2, 0)] // [ FF ] is always invalid
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithLargeInvalidBuffers(string input, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
+ {
+ // These test cases are for the "fast processing" code which is the main loop of GetIndexOfFirstInvalidUtf8Sequence,
+ // so inputs should be less >= 4 bytes.
+
+ Assert.True(input.Length >= 8);
+
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, expectedRetVal, expectedRuneCount, expectedSurrogatePairCount);
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithOverlongTwoByteSequences_ReturnsInvalid()
+ {
+ // [ C0 ] is never a valid byte, indicates overlong 2-byte sequence
+ // We'll test that [ C0 ] [ 00..FF ] is treated as invalid
+
+ for (int i = 0; i < 256; i++)
+ {
+ AssertIsInvalidTwoByteSequence(new byte[] { 0xC0, (byte)i });
+ }
+
+ // [ C1 ] is never a valid byte, indicates overlong 2-byte sequence
+ // We'll test that [ C1 ] [ 00..FF ] is treated as invalid
+
+ for (int i = 0; i < 256; i++)
+ {
+ AssertIsInvalidTwoByteSequence(new byte[] { 0xC1, (byte)i });
+ }
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithImproperlyTerminatedTwoByteSequences_ReturnsInvalid()
+ {
+ // Test [ C2..DF ] [ 00..7F ] and [ C2..DF ] [ C0..FF ]
+
+ for (int i = 0xC2; i < 0xDF; i++)
+ {
+ for (int j = 0; j < 0x80; j++)
+ {
+ AssertIsInvalidTwoByteSequence(new byte[] { (byte)i, (byte)j });
+ }
+ for (int j = 0xC0; j < 0x100; j++)
+ {
+ AssertIsInvalidTwoByteSequence(new byte[] { (byte)i, (byte)j });
+ }
+ }
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithOverlongThreeByteSequences_ReturnsInvalid()
+ {
+ // [ E0 ] [ 80..9F ] [ 80..BF ] is overlong 3-byte sequence
+
+ for (int i = 0x00; i < 0xA0; i++)
+ {
+ AssertIsInvalidThreeByteSequence(new byte[] { 0xE0, (byte)i, 0x80 });
+ }
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithSurrogateThreeByteSequences_ReturnsInvalid()
+ {
+ // [ ED ] [ A0..BF ] [ 80..BF ] is surrogate 3-byte sequence
+
+ for (int i = 0xA0; i < 0x100; i++)
+ {
+ AssertIsInvalidThreeByteSequence(new byte[] { 0xED, (byte)i, 0x80 });
+ }
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithImproperlyTerminatedThreeByteSequence_ReturnsInvalid()
+ {
+ // [ E0..EF ] [ 80..BF ] [ !(80..BF) ] is improperly terminated 3-byte sequence
+
+ for (int i = 0xE0; i < 0xF0; i++)
+ {
+ for (int j = 0x00; j < 0x80; j++)
+ {
+ // Use both '9F' and 'A0' to make sure at least one isn't caught by overlong / surrogate checks
+ AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0x9F, (byte)j });
+ AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0xA0, (byte)j });
+ }
+ for (int j = 0xC0; j < 0x100; j++)
+ {
+ // Use both '9F' and 'A0' to make sure at least one isn't caught by overlong / surrogate checks
+ AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0x9F, (byte)j });
+ AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0xA0, (byte)j });
+ }
+ }
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithOverlongFourByteSequences_ReturnsInvalid()
+ {
+ // [ F0 ] [ 80..8F ] [ 80..BF ] [ 80..BF ] is overlong 4-byte sequence
+
+ for (int i = 0x00; i < 0x90; i++)
+ {
+ AssertIsInvalidFourByteSequence(new byte[] { 0xF0, (byte)i, 0x80, 0x80 });
+ }
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithOutOfRangeFourByteSequences_ReturnsInvalid()
+ {
+ // [ F4 ] [ 90..BF ] [ 80..BF ] [ 80..BF ] is out-of-range 4-byte sequence
+
+ for (int i = 0x90; i < 0x100; i++)
+ {
+ AssertIsInvalidFourByteSequence(new byte[] { 0xF4, (byte)i, 0x80, 0x80 });
+ }
+ }
+
+ [Fact]
+ public void GetIndexOfFirstInvalidUtf8Sequence_WithInvalidFourByteSequence_ReturnsInvalid()
+ {
+ // [ F0..F4 ] [ !(80..BF) ] [ !(80..BF) ] [ !(80..BF) ] is improperly terminated 4-byte sequence
+
+ for (int i = 0xF0; i < 0xF5; i++)
+ {
+ for (int j = 0x00; j < 0x80; j++)
+ {
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, (byte)j, 0x80, 0x80 });
+
+ // Use both '8F' and '90' to make sure at least one isn't caught by overlong / out-of-range checks
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, (byte)j, 0x80 });
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, (byte)j, 0x80 });
+
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, 0x80, (byte)j });
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, 0x80, (byte)j });
+ }
+ for (int j = 0xC0; j < 0x100; j++)
+ {
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, (byte)j, 0x80, 0x80 });
+
+ // Use both '8F' and '90' to make sure at least one isn't caught by overlong / out-of-range checks
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, (byte)j, 0x80 });
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, (byte)j, 0x80 });
+
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, 0x80, (byte)j });
+ AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, 0x80, (byte)j });
+ }
+ }
+ }
+
+ private static void AssertIsInvalidTwoByteSequence(byte[] invalidSequence)
+ {
+ Assert.Equal(2, invalidSequence.Length);
+
+ byte[] knownGoodBytes = Utf8Tests.DecodeHex(E_ACUTE);
+
+ byte[] toTest = invalidSequence.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at start of first DWORD
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 0, 0, 0);
+
+ toTest = knownGoodBytes.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at end of first DWORD
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 2, 1, 0);
+
+ // Run the same tests but with extra data at the beginning so that we're inside one of
+ // the 2-byte processing "hot loop" code paths.
+
+ toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at start of next DWORD
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 4, 2, 0);
+
+ toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at end of next DWORD
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 6, 3, 0);
+ }
+
+ private static void AssertIsInvalidThreeByteSequence(byte[] invalidSequence)
+ {
+ Assert.Equal(3, invalidSequence.Length);
+
+ byte[] knownGoodBytes = Utf8Tests.DecodeHex(EURO_SYMBOL);
+
+ byte[] toTest = invalidSequence.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at start of first DWORD
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 0, 0, 0);
+
+ // Run the same tests but with extra data at the beginning so that we're inside one of
+ // the 3-byte processing "hot loop" code paths.
+
+ toTest = knownGoodBytes.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // straddling first and second DWORDs
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 3, 1, 0);
+
+ toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // straddling second and third DWORDs
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 6, 2, 0);
+
+ toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at end of third DWORD
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 9, 3, 0);
+ }
+
+ private static void AssertIsInvalidFourByteSequence(byte[] invalidSequence)
+ {
+ Assert.Equal(4, invalidSequence.Length);
+
+ byte[] knownGoodBytes = Utf8Tests.DecodeHex(GRINNING_FACE);
+
+ byte[] toTest = invalidSequence.Concat(invalidSequence).Concat(knownGoodBytes).ToArray();
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 0, 0, 0);
+
+ toTest = knownGoodBytes.Concat(invalidSequence).Concat(knownGoodBytes).ToArray();
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 4, 1, 1);
+ }
+
+ private static void GetIndexOfFirstInvalidUtf8Sequence_Test_Core(string inputHex, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
+ {
+ byte[] inputBytes = Utf8Tests.DecodeHex(inputHex);
+
+ // Run the test normally
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(inputBytes, expectedRetVal, expectedRuneCount, expectedSurrogatePairCount);
+
+ // Then run the test with a bunch of ASCII data at the beginning (to exercise the vectorized code paths)
+ inputBytes = Enumerable.Repeat((byte)'x', 128).Concat(inputBytes).ToArray();
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(inputBytes, (expectedRetVal < 0) ? expectedRetVal : (expectedRetVal + 128), expectedRuneCount + 128, expectedSurrogatePairCount);
+
+ // Then put a few more ASCII bytes at the beginning (to test that offsets are properly handled)
+ inputBytes = Enumerable.Repeat((byte)'x', 7).Concat(inputBytes).ToArray();
+ GetIndexOfFirstInvalidUtf8Sequence_Test_Core(inputBytes, (expectedRetVal < 0) ? expectedRetVal : (expectedRetVal + 135), expectedRuneCount + 135, expectedSurrogatePairCount);
+ }
+
+ private static unsafe void GetIndexOfFirstInvalidUtf8Sequence_Test_Core(byte[] input, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
+ {
+ // Arrange
+
+ using BoundedMemory<byte> boundedMemory = BoundedMemory.AllocateFromExistingData(input);
+ boundedMemory.MakeReadonly();
+
+ // Act
+
+ int actualRetVal;
+ int actualSurrogatePairCount;
+ int actualRuneCount;
+
+ fixed (byte* pInputBuffer = &MemoryMarshal.GetReference(boundedMemory.Span))
+ {
+ byte* pFirstInvalidByte = _getPointerToFirstInvalidByteFn.Value(pInputBuffer, input.Length, out int utf16CodeUnitCountAdjustment, out int scalarCountAdjustment);
+
+ long ptrDiff = pFirstInvalidByte - pInputBuffer;
+ Assert.True((ulong)ptrDiff <= (uint)input.Length, "ptrDiff was outside expected range.");
+
+ Assert.True(utf16CodeUnitCountAdjustment <= 0, "UTF-16 code unit count adjustment must be 0 or negative.");
+ Assert.True(scalarCountAdjustment <= 0, "Scalar count adjustment must be 0 or negative.");
+
+ actualRetVal = (ptrDiff == input.Length) ? -1 : (int)ptrDiff;
+
+ // The last two 'out' parameters are:
+ // a) The number to be added to the "bytes processed" return value to come up with the total UTF-16 code unit count, and
+ // b) The number to be added to the "total UTF-16 code unit count" value to come up with the total scalar count.
+
+ int totalUtf16CodeUnitCount = (int)ptrDiff + utf16CodeUnitCountAdjustment;
+ actualRuneCount = totalUtf16CodeUnitCount + scalarCountAdjustment;
+
+ // Surrogate pair count is number of UTF-16 code units less the number of scalars.
+
+ actualSurrogatePairCount = totalUtf16CodeUnitCount - actualRuneCount;
+ }
+
+ // Assert
+
+ Assert.Equal(expectedRetVal, actualRetVal);
+ Assert.Equal(expectedRuneCount, actualRuneCount);
+ Assert.Equal(expectedSurrogatePairCount, actualSurrogatePairCount);
+ }
+
+ private static Lazy<GetPointerToFirstInvalidByteDel> CreateGetPointerToFirstInvalidByteFn()
+ {
+ return new Lazy<GetPointerToFirstInvalidByteDel>(() =>
+ {
+ Type utf8UtilityType = typeof(Utf8).Assembly.GetType("System.Text.Unicode.Utf8Utility");
+
+ if (utf8UtilityType is null)
+ {
+ throw new Exception("Couldn't find Utf8Utility type in System.Private.CoreLib.");
+ }
+
+ MethodInfo methodInfo = utf8UtilityType.GetMethod("GetPointerToFirstInvalidByte", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
+
+ if (methodInfo is null)
+ {
+ throw new Exception("Couldn't find GetPointerToFirstInvalidByte method on Utf8Utility.");
+ }
+
+ return (GetPointerToFirstInvalidByteDel)methodInfo.CreateDelegate(typeof(GetPointerToFirstInvalidByteDel));
+ });
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using Xunit;
-
-namespace System.Text.Unicode.Tests
-{
- public partial class Utf8UtilityTests
- {
- private unsafe delegate byte* GetPointerToFirstInvalidByteDel(byte* pInputBuffer, int inputLength, out int utf16CodeUnitCountAdjustment, out int scalarCountAdjustment);
- private static readonly Lazy<GetPointerToFirstInvalidByteDel> _getPointerToFirstInvalidByteFn = CreateGetPointerToFirstInvalidByteFn();
-
- private const string X = "58"; // U+0058 LATIN CAPITAL LETTER X, 1 byte
- private const string Y = "59"; // U+0058 LATIN CAPITAL LETTER Y, 1 byte
- private const string Z = "5A"; // U+0058 LATIN CAPITAL LETTER Z, 1 byte
- private const string E_ACUTE = "C3A9"; // U+00E9 LATIN SMALL LETTER E WITH ACUTE, 2 bytes
- private const string EURO_SYMBOL = "E282AC"; // U+20AC EURO SIGN, 3 bytes
- private const string GRINNING_FACE = "F09F9880"; // U+1F600 GRINNING FACE, 4 bytes
-
- [Theory]
- [InlineData("", 0, 0)] // empty string is OK
- [InlineData(X, 1, 0)]
- [InlineData(X + Y, 2, 0)]
- [InlineData(X + Y + Z, 3, 0)]
- [InlineData(E_ACUTE, 1, 0)]
- [InlineData(X + E_ACUTE, 2, 0)]
- [InlineData(E_ACUTE + X, 2, 0)]
- [InlineData(EURO_SYMBOL, 1, 0)]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithSmallValidBuffers(string input, int expectedRuneCount, int expectedSurrogatePairCount)
- {
- // These test cases are for the "slow processing" code path at the end of GetIndexOfFirstInvalidUtf8Sequence,
- // so inputs should be less than 4 bytes.
-
- Assert.InRange(input.Length, 0, 6);
-
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, -1 /* expectedRetVal */, expectedRuneCount, expectedSurrogatePairCount);
- }
-
- [Theory]
- [InlineData("80", 0, 0, 0)] // sequence cannot begin with continuation character
- [InlineData("8182", 0, 0, 0)] // sequence cannot begin with continuation character
- [InlineData("838485", 0, 0, 0)] // sequence cannot begin with continuation character
- [InlineData(X + "80", 1, 1, 0)] // sequence cannot begin with continuation character
- [InlineData(X + "8182", 1, 1, 0)] // sequence cannot begin with continuation character
- [InlineData("C0", 0, 0, 0)] // [ C0 ] is always invalid
- [InlineData("C080", 0, 0, 0)] // [ C0 ] is always invalid
- [InlineData("C08081", 0, 0, 0)] // [ C0 ] is always invalid
- [InlineData(X + "C1", 1, 1, 0)] // [ C1 ] is always invalid
- [InlineData(X + "C180", 1, 1, 0)] // [ C1 ] is always invalid
- [InlineData("C2", 0, 0, 0)] // [ C2 ] is improperly terminated
- [InlineData(X + "C27F", 1, 1, 0)] // [ C2 ] is improperly terminated
- [InlineData(X + "E282", 1, 1, 0)] // [ E2 82 ] is improperly terminated
- [InlineData("E2827F", 0, 0, 0)] // [ E2 82 ] is improperly terminated
- [InlineData("E09F80", 0, 0, 0)] // [ E0 9F ... ] is overlong
- [InlineData("E0C080", 0, 0, 0)] // [ E0 ] is improperly terminated
- [InlineData("ED7F80", 0, 0, 0)] // [ ED ] is improperly terminated
- [InlineData("EDA080", 0, 0, 0)] // [ ED A0 ... ] is surrogate
- public void GetIndexOfFirstInvalidUtf8Sequence_WithSmallInvalidBuffers(string input, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
- {
- // These test cases are for the "slow processing" code path at the end of GetIndexOfFirstInvalidUtf8Sequence,
- // so inputs should be less than 4 bytes.
-
- Assert.InRange(input.Length, 0, 6);
-
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, expectedRetVal, expectedRuneCount, expectedSurrogatePairCount);
- }
-
- [Theory]
- [InlineData(E_ACUTE + "21222324" + "303132333435363738393A3B3C3D3E3F", 21, 0)] // Loop unrolling at end of buffer
- [InlineData(E_ACUTE + "21222324" + "303132333435363738393A3B3C3D3E3F" + "3031323334353637" + E_ACUTE + "38393A3B3C3D3E3F", 38, 0)] // Loop unrolling interrupted by non-ASCII
- [InlineData("212223" + E_ACUTE + "30313233", 8, 0)] // 3 ASCII bytes followed by non-ASCII
- [InlineData("2122" + E_ACUTE + "30313233", 7, 0)] // 2 ASCII bytes followed by non-ASCII
- [InlineData("21" + E_ACUTE + "30313233", 6, 0)] // 1 ASCII byte followed by non-ASCII
- [InlineData(E_ACUTE + E_ACUTE + E_ACUTE + E_ACUTE, 4, 0)] // 4x 2-byte sequences, exercises optimization code path in 2-byte sequence processing
- [InlineData(E_ACUTE + E_ACUTE + E_ACUTE + "5051", 5, 0)] // 3x 2-byte sequences + 2 ASCII bytes, exercises optimization code path in 2-byte sequence processing
- [InlineData(E_ACUTE + "5051", 3, 0)] // single 2-byte sequence + 2 trailing ASCII bytes, exercises draining logic in 2-byte sequence processing
- [InlineData(E_ACUTE + "50" + E_ACUTE + "304050", 6, 0)] // single 2-byte sequences + 1 trailing ASCII byte + 2-byte sequence, exercises draining logic in 2-byte sequence processing
- [InlineData(EURO_SYMBOL + "20", 2, 0)] // single 3-byte sequence + 1 trailing ASCII byte, exercises draining logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL + "203040", 4, 0)] // single 3-byte sequence + 3 trailing ASCII byte, exercises draining logic and "running out of data" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL, 3, 0)] // 3x 3-byte sequences, exercises "stay within 3-byte loop" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL, 4, 0)] // 4x 3-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL + EURO_SYMBOL + EURO_SYMBOL + E_ACUTE, 4, 0)] // 3x 3-byte sequences + single 2-byte sequence, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
- [InlineData(EURO_SYMBOL + EURO_SYMBOL + E_ACUTE + E_ACUTE + E_ACUTE + E_ACUTE, 6, 0)] // 2x 3-byte sequences + 4x 2-byte sequences, exercises "consume multiple bytes at a time" logic in 3-byte sequence processing
- [InlineData(GRINNING_FACE + GRINNING_FACE, 2, 2)] // 2x 4-byte sequences, exercises 4-byte sequence processing
- [InlineData(GRINNING_FACE + "303132", 4, 1)] // single 4-byte sequence + 3 ASCII bytes, exercises 4-byte sequence processing and draining logic
- [InlineData("F09FA4B8" + "F09F8FBD" + "E2808D" + "E29980" + "EFB88F", 5, 2)] // U+1F938 U+1F3FD U+200D U+2640 U+FE0F WOMAN CARTWHEELING: MEDIUM SKIN TONE, exercising switching between multiple sequence lengths
- public void GetIndexOfFirstInvalidUtf8Sequence_WithLargeValidBuffers(string input, int expectedRuneCount, int expectedSurrogatePairCount)
- {
- // These test cases are for the "fast processing" code which is the main loop of GetIndexOfFirstInvalidUtf8Sequence,
- // so inputs should be less >= 4 bytes.
-
- Assert.True(input.Length >= 8);
-
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, -1 /* expectedRetVal */, expectedRuneCount, expectedSurrogatePairCount);
- }
-
- [Theory]
- [InlineData("3031" + "80" + "202122232425", 2, 2, 0)] // Continuation character at start of sequence should match no bitmask
- [InlineData("3031" + "C080" + "2021222324", 2, 2, 0)] // Overlong 2-byte sequence at start of DWORD
- [InlineData("3031" + "C180" + "2021222324", 2, 2, 0)] // Overlong 2-byte sequence at start of DWORD
- [InlineData("C280" + "C180", 2, 1, 0)] // Overlong 2-byte sequence at end of DWORD
- [InlineData("C27F" + "C280", 0, 0, 0)] // Improperly terminated 2-byte sequence at start of DWORD
- [InlineData("C2C0" + "C280", 0, 0, 0)] // Improperly terminated 2-byte sequence at start of DWORD
- [InlineData("C280" + "C27F", 2, 1, 0)] // Improperly terminated 2-byte sequence at end of DWORD
- [InlineData("C280" + "C2C0", 2, 1, 0)] // Improperly terminated 2-byte sequence at end of DWORD
- [InlineData("C280" + "C280" + "80203040", 4, 2, 0)] // Continuation character at start of sequence, within "stay in 2-byte processing" optimization
- [InlineData("C280" + "C280" + "C180" + "C280", 4, 2, 0)] // Overlong 2-byte sequence at start of DWORD, within "stay in 2-byte processing" optimization
- [InlineData("C280" + "C280" + "C280" + "C180", 6, 3, 0)] // Overlong 2-byte sequence at end of DWORD, within "stay in 2-byte processing" optimization
- [InlineData("3031" + "E09F80" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Overlong 3-byte sequence at start of DWORD
- [InlineData("3031" + "E07F80" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "E0C080" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "E17F80" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "E1C080" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Improperly terminated 3-byte sequence at start of DWORD
- [InlineData("3031" + "EDA080" + EURO_SYMBOL + EURO_SYMBOL, 2, 2, 0)] // Surrogate 3-byte sequence at start of DWORD
- [InlineData("3031" + "E69C88" + "E59B" + "E69C88", 5, 3, 0)] // Incomplete 3-byte sequence surrounded by valid 3-byte sequences
- [InlineData("E78B80" + "80", 3, 1, 0)] // Valid 3-byte sequence followed by standalone continuation byte
- [InlineData("3031" + "F5808080", 2, 2, 0)] // [ F5 ] is always invalid
- [InlineData("3031" + "F6808080", 2, 2, 0)] // [ F6 ] is always invalid
- [InlineData("3031" + "F7808080", 2, 2, 0)] // [ F7 ] is always invalid
- [InlineData("3031" + "F8808080", 2, 2, 0)] // [ F8 ] is always invalid
- [InlineData("3031" + "F9808080", 2, 2, 0)] // [ F9 ] is always invalid
- [InlineData("3031" + "FA808080", 2, 2, 0)] // [ FA ] is always invalid
- [InlineData("3031" + "FB808080", 2, 2, 0)] // [ FB ] is always invalid
- [InlineData("3031" + "FC808080", 2, 2, 0)] // [ FC ] is always invalid
- [InlineData("3031" + "FD808080", 2, 2, 0)] // [ FD ] is always invalid
- [InlineData("3031" + "FE808080", 2, 2, 0)] // [ FE ] is always invalid
- [InlineData("3031" + "FF808080", 2, 2, 0)] // [ FF ] is always invalid
- public void GetIndexOfFirstInvalidUtf8Sequence_WithLargeInvalidBuffers(string input, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
- {
- // These test cases are for the "fast processing" code which is the main loop of GetIndexOfFirstInvalidUtf8Sequence,
- // so inputs should be less >= 4 bytes.
-
- Assert.True(input.Length >= 8);
-
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(input, expectedRetVal, expectedRuneCount, expectedSurrogatePairCount);
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithOverlongTwoByteSequences_ReturnsInvalid()
- {
- // [ C0 ] is never a valid byte, indicates overlong 2-byte sequence
- // We'll test that [ C0 ] [ 00..FF ] is treated as invalid
-
- for (int i = 0; i < 256; i++)
- {
- AssertIsInvalidTwoByteSequence(new byte[] { 0xC0, (byte)i });
- }
-
- // [ C1 ] is never a valid byte, indicates overlong 2-byte sequence
- // We'll test that [ C1 ] [ 00..FF ] is treated as invalid
-
- for (int i = 0; i < 256; i++)
- {
- AssertIsInvalidTwoByteSequence(new byte[] { 0xC1, (byte)i });
- }
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithImproperlyTerminatedTwoByteSequences_ReturnsInvalid()
- {
- // Test [ C2..DF ] [ 00..7F ] and [ C2..DF ] [ C0..FF ]
-
- for (int i = 0xC2; i < 0xDF; i++)
- {
- for (int j = 0; j < 0x80; j++)
- {
- AssertIsInvalidTwoByteSequence(new byte[] { (byte)i, (byte)j });
- }
- for (int j = 0xC0; j < 0x100; j++)
- {
- AssertIsInvalidTwoByteSequence(new byte[] { (byte)i, (byte)j });
- }
- }
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithOverlongThreeByteSequences_ReturnsInvalid()
- {
- // [ E0 ] [ 80..9F ] [ 80..BF ] is overlong 3-byte sequence
-
- for (int i = 0x00; i < 0xA0; i++)
- {
- AssertIsInvalidThreeByteSequence(new byte[] { 0xE0, (byte)i, 0x80 });
- }
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithSurrogateThreeByteSequences_ReturnsInvalid()
- {
- // [ ED ] [ A0..BF ] [ 80..BF ] is surrogate 3-byte sequence
-
- for (int i = 0xA0; i < 0x100; i++)
- {
- AssertIsInvalidThreeByteSequence(new byte[] { 0xED, (byte)i, 0x80 });
- }
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithImproperlyTerminatedThreeByteSequence_ReturnsInvalid()
- {
- // [ E0..EF ] [ 80..BF ] [ !(80..BF) ] is improperly terminated 3-byte sequence
-
- for (int i = 0xE0; i < 0xF0; i++)
- {
- for (int j = 0x00; j < 0x80; j++)
- {
- // Use both '9F' and 'A0' to make sure at least one isn't caught by overlong / surrogate checks
- AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0x9F, (byte)j });
- AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0xA0, (byte)j });
- }
- for (int j = 0xC0; j < 0x100; j++)
- {
- // Use both '9F' and 'A0' to make sure at least one isn't caught by overlong / surrogate checks
- AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0x9F, (byte)j });
- AssertIsInvalidThreeByteSequence(new byte[] { (byte)i, 0xA0, (byte)j });
- }
- }
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithOverlongFourByteSequences_ReturnsInvalid()
- {
- // [ F0 ] [ 80..8F ] [ 80..BF ] [ 80..BF ] is overlong 4-byte sequence
-
- for (int i = 0x00; i < 0x90; i++)
- {
- AssertIsInvalidFourByteSequence(new byte[] { 0xF0, (byte)i, 0x80, 0x80 });
- }
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithOutOfRangeFourByteSequences_ReturnsInvalid()
- {
- // [ F4 ] [ 90..BF ] [ 80..BF ] [ 80..BF ] is out-of-range 4-byte sequence
-
- for (int i = 0x90; i < 0x100; i++)
- {
- AssertIsInvalidFourByteSequence(new byte[] { 0xF4, (byte)i, 0x80, 0x80 });
- }
- }
-
- [Fact]
- public void GetIndexOfFirstInvalidUtf8Sequence_WithInvalidFourByteSequence_ReturnsInvalid()
- {
- // [ F0..F4 ] [ !(80..BF) ] [ !(80..BF) ] [ !(80..BF) ] is improperly terminated 4-byte sequence
-
- for (int i = 0xF0; i < 0xF5; i++)
- {
- for (int j = 0x00; j < 0x80; j++)
- {
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, (byte)j, 0x80, 0x80 });
-
- // Use both '8F' and '90' to make sure at least one isn't caught by overlong / out-of-range checks
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, (byte)j, 0x80 });
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, (byte)j, 0x80 });
-
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, 0x80, (byte)j });
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, 0x80, (byte)j });
- }
- for (int j = 0xC0; j < 0x100; j++)
- {
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, (byte)j, 0x80, 0x80 });
-
- // Use both '8F' and '90' to make sure at least one isn't caught by overlong / out-of-range checks
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, (byte)j, 0x80 });
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, (byte)j, 0x80 });
-
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0x9F, 0x80, (byte)j });
- AssertIsInvalidFourByteSequence(new byte[] { (byte)i, 0xA0, 0x80, (byte)j });
- }
- }
- }
-
- private static void AssertIsInvalidTwoByteSequence(byte[] invalidSequence)
- {
- Assert.Equal(2, invalidSequence.Length);
-
- byte[] knownGoodBytes = Utf8Tests.DecodeHex(E_ACUTE);
-
- byte[] toTest = invalidSequence.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at start of first DWORD
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 0, 0, 0);
-
- toTest = knownGoodBytes.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at end of first DWORD
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 2, 1, 0);
-
- // Run the same tests but with extra data at the beginning so that we're inside one of
- // the 2-byte processing "hot loop" code paths.
-
- toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at start of next DWORD
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 4, 2, 0);
-
- toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at end of next DWORD
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 6, 3, 0);
- }
-
- private static void AssertIsInvalidThreeByteSequence(byte[] invalidSequence)
- {
- Assert.Equal(3, invalidSequence.Length);
-
- byte[] knownGoodBytes = Utf8Tests.DecodeHex(EURO_SYMBOL);
-
- byte[] toTest = invalidSequence.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at start of first DWORD
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 0, 0, 0);
-
- // Run the same tests but with extra data at the beginning so that we're inside one of
- // the 3-byte processing "hot loop" code paths.
-
- toTest = knownGoodBytes.Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // straddling first and second DWORDs
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 3, 1, 0);
-
- toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // straddling second and third DWORDs
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 6, 2, 0);
-
- toTest = knownGoodBytes.Concat(knownGoodBytes).Concat(knownGoodBytes).Concat(invalidSequence).Concat(knownGoodBytes).ToArray(); // at end of third DWORD
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 9, 3, 0);
- }
-
- private static void AssertIsInvalidFourByteSequence(byte[] invalidSequence)
- {
- Assert.Equal(4, invalidSequence.Length);
-
- byte[] knownGoodBytes = Utf8Tests.DecodeHex(GRINNING_FACE);
-
- byte[] toTest = invalidSequence.Concat(invalidSequence).Concat(knownGoodBytes).ToArray();
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 0, 0, 0);
-
- toTest = knownGoodBytes.Concat(invalidSequence).Concat(knownGoodBytes).ToArray();
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(toTest, 4, 1, 1);
- }
-
- private static void GetIndexOfFirstInvalidUtf8Sequence_Test_Core(string inputHex, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
- {
- byte[] inputBytes = Utf8Tests.DecodeHex(inputHex);
-
- // Run the test normally
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(inputBytes, expectedRetVal, expectedRuneCount, expectedSurrogatePairCount);
-
- // Then run the test with a bunch of ASCII data at the beginning (to exercise the vectorized code paths)
- inputBytes = Enumerable.Repeat((byte)'x', 128).Concat(inputBytes).ToArray();
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(inputBytes, (expectedRetVal < 0) ? expectedRetVal : (expectedRetVal + 128), expectedRuneCount + 128, expectedSurrogatePairCount);
-
- // Then put a few more ASCII bytes at the beginning (to test that offsets are properly handled)
- inputBytes = Enumerable.Repeat((byte)'x', 7).Concat(inputBytes).ToArray();
- GetIndexOfFirstInvalidUtf8Sequence_Test_Core(inputBytes, (expectedRetVal < 0) ? expectedRetVal : (expectedRetVal + 135), expectedRuneCount + 135, expectedSurrogatePairCount);
- }
-
- private static unsafe void GetIndexOfFirstInvalidUtf8Sequence_Test_Core(byte[] input, int expectedRetVal, int expectedRuneCount, int expectedSurrogatePairCount)
- {
- // Arrange
-
- using BoundedMemory<byte> boundedMemory = BoundedMemory.AllocateFromExistingData(input);
- boundedMemory.MakeReadonly();
-
- // Act
-
- int actualRetVal;
- int actualSurrogatePairCount;
- int actualRuneCount;
-
- fixed (byte* pInputBuffer = &MemoryMarshal.GetReference(boundedMemory.Span))
- {
- byte* pFirstInvalidByte = _getPointerToFirstInvalidByteFn.Value(pInputBuffer, input.Length, out int utf16CodeUnitCountAdjustment, out int scalarCountAdjustment);
-
- long ptrDiff = pFirstInvalidByte - pInputBuffer;
- Assert.True((ulong)ptrDiff <= (uint)input.Length, "ptrDiff was outside expected range.");
-
- Assert.True(utf16CodeUnitCountAdjustment <= 0, "UTF-16 code unit count adjustment must be 0 or negative.");
- Assert.True(scalarCountAdjustment <= 0, "Scalar count adjustment must be 0 or negative.");
-
- actualRetVal = (ptrDiff == input.Length) ? -1 : (int)ptrDiff;
-
- // The last two 'out' parameters are:
- // a) The number to be added to the "bytes processed" return value to come up with the total UTF-16 code unit count, and
- // b) The number to be added to the "total UTF-16 code unit count" value to come up with the total scalar count.
-
- int totalUtf16CodeUnitCount = (int)ptrDiff + utf16CodeUnitCountAdjustment;
- actualRuneCount = totalUtf16CodeUnitCount + scalarCountAdjustment;
-
- // Surrogate pair count is number of UTF-16 code units less the number of scalars.
-
- actualSurrogatePairCount = totalUtf16CodeUnitCount - actualRuneCount;
- }
-
- // Assert
-
- Assert.Equal(expectedRetVal, actualRetVal);
- Assert.Equal(expectedRuneCount, actualRuneCount);
- Assert.Equal(expectedSurrogatePairCount, actualSurrogatePairCount);
- }
-
- private static Lazy<GetPointerToFirstInvalidByteDel> CreateGetPointerToFirstInvalidByteFn()
- {
- return new Lazy<GetPointerToFirstInvalidByteDel>(() =>
- {
- Type utf8UtilityType = typeof(Utf8).Assembly.GetType("System.Text.Unicode.Utf8Utility");
-
- if (utf8UtilityType is null)
- {
- throw new Exception("Couldn't find Utf8Utility type in System.Private.CoreLib.");
- }
-
- MethodInfo methodInfo = utf8UtilityType.GetMethod("GetPointerToFirstInvalidByte", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
-
- if (methodInfo is null)
- {
- throw new Exception("Couldn't find GetPointerToFirstInvalidByte method on Utf8Utility.");
- }
-
- return (GetPointerToFirstInvalidByteDel)methodInfo.CreateDelegate(typeof(GetPointerToFirstInvalidByteDel));
- });
- }
- }
-}
namespace System.Tests
{
- public partial class TimeSpanTests
+ public class TimeSpanTests
{
[Fact]
public static void MaxValue()
{
Assert.Equal(expected, Math.Sign(timeSpan1.CompareTo(obj)));
}
+
+ public static IEnumerable<object[]> MultiplicationTestData()
+ {
+ yield return new object[] {new TimeSpan(2, 30, 0), 2.0, new TimeSpan(5, 0, 0)};
+ yield return new object[] {new TimeSpan(14, 2, 30, 0), 192.0, TimeSpan.FromDays(2708)};
+ yield return new object[] {TimeSpan.FromDays(366), Math.PI, new TimeSpan(993446995288779)};
+ yield return new object[] {TimeSpan.FromDays(366), -Math.E, new TimeSpan(-859585952922633)};
+ yield return new object[] {TimeSpan.FromDays(29.530587981), 13.0, TimeSpan.FromDays(29.530587981 * 13.0) };
+ yield return new object[] {TimeSpan.FromDays(-29.530587981), -12.0, TimeSpan.FromDays(-29.530587981 * -12.0) };
+ yield return new object[] {TimeSpan.FromDays(-29.530587981), 0.0, TimeSpan.Zero};
+ yield return new object[] {TimeSpan.MaxValue, 0.5, TimeSpan.FromTicks((long)(long.MaxValue * 0.5))};
+ }
+
+ // ParseDifferentLengthFractionWithLeadingZerosData mainly testing the behavior we have fixed in net core
+ // which is the way we normalize the parsed fraction and possibly rounding it.
+ public static IEnumerable<object[]> ParseDifferentLengthFractionWithLeadingZerosData()
+ {
+ yield return new object[] {"00:00:00.00000001", new TimeSpan(0)};
+ yield return new object[] {"00:00:00.00000005", new TimeSpan(1)};
+ yield return new object[] {"00:00:00.09999999", new TimeSpan(1_000_000)};
+ yield return new object[] {"00:00:00.0268435455", new TimeSpan(268435)};
+ yield return new object[] {"00:00:00.01", new TimeSpan(1_00_000)};
+ yield return new object[] {"0:00:00.01000000", new TimeSpan(100_000)};
+ yield return new object[] {"0:00:00.010000000", new TimeSpan(100_000)};
+ yield return new object[] {"0:00:00.0123456", new TimeSpan(123456)};
+ yield return new object[] {"0:00:00.00123456", new TimeSpan(12346)};
+ yield return new object[] {"0:00:00.00000098", new TimeSpan(10)};
+ yield return new object[] {"0:00:00.00000099", new TimeSpan(10)};
+ }
+
+ [Theory, MemberData(nameof(ParseDifferentLengthFractionWithLeadingZerosData))]
+ public static void Multiplication(string input, TimeSpan expected)
+ {
+ Assert.Equal(expected, TimeSpan.Parse(input, CultureInfo.InvariantCulture));
+ Assert.Equal(expected, TimeSpan.ParseExact(input, "g", CultureInfo.InvariantCulture));
+ }
+
+ [Theory, MemberData(nameof(MultiplicationTestData))]
+ public static void Multiplication(TimeSpan timeSpan, double factor, TimeSpan expected)
+ {
+ Assert.Equal(expected, timeSpan * factor);
+ Assert.Equal(expected, factor * timeSpan);
+ }
+
+ [Fact]
+ public static void OverflowingMultiplication()
+ {
+ Assert.Throws<OverflowException>(() => TimeSpan.MaxValue * 1.000000001);
+ Assert.Throws<OverflowException>(() => -1.000000001 * TimeSpan.MaxValue);
+ }
+
+ [Fact]
+ public static void NaNMultiplication()
+ {
+ AssertExtensions.Throws<ArgumentException>("factor", () => TimeSpan.FromDays(1) * double.NaN);
+ AssertExtensions.Throws<ArgumentException>("factor", () => double.NaN * TimeSpan.FromDays(1));
+ }
+
+ [Theory, MemberData(nameof(MultiplicationTestData))]
+ public static void Division(TimeSpan timeSpan, double factor, TimeSpan expected)
+ {
+ Assert.Equal(factor, expected / timeSpan, 14);
+ double divisor = 1.0 / factor;
+ Assert.Equal(expected, timeSpan / divisor);
+ }
+
+ [Fact]
+ public static void DivideByZero()
+ {
+ Assert.Throws<OverflowException>(() => TimeSpan.FromDays(1) / 0);
+ Assert.Throws<OverflowException>(() => TimeSpan.FromDays(-1) / 0);
+ Assert.Throws<OverflowException>(() => TimeSpan.Zero / 0);
+ Assert.Equal(double.PositiveInfinity, TimeSpan.FromDays(1) / TimeSpan.Zero);
+ Assert.Equal(double.NegativeInfinity, TimeSpan.FromDays(-1) / TimeSpan.Zero);
+ Assert.True(double.IsNaN(TimeSpan.Zero / TimeSpan.Zero));
+ }
+
+ [Fact]
+ public static void NaNDivision()
+ {
+ AssertExtensions.Throws<ArgumentException>("divisor", () => TimeSpan.FromDays(1) / double.NaN);
+ }
+
+ [Theory, MemberData(nameof(MultiplicationTestData))]
+ public static void NamedMultiplication(TimeSpan timeSpan, double factor, TimeSpan expected)
+ {
+ Assert.Equal(expected, timeSpan.Multiply(factor));
+ }
+
+ [Fact]
+ public static void NamedOverflowingMultiplication()
+ {
+ Assert.Throws<OverflowException>(() => TimeSpan.MaxValue.Multiply(1.000000001));
+ }
+
+ [Fact]
+ public static void NamedNaNMultiplication()
+ {
+ AssertExtensions.Throws<ArgumentException>("factor", () => TimeSpan.FromDays(1).Multiply(double.NaN));
+ }
+
+ [Theory, MemberData(nameof(MultiplicationTestData))]
+ public static void NamedDivision(TimeSpan timeSpan, double factor, TimeSpan expected)
+ {
+ Assert.Equal(factor, expected.Divide(timeSpan), 14);
+ double divisor = 1.0 / factor;
+ Assert.Equal(expected, timeSpan.Divide(divisor));
+ }
+
+ [Fact]
+ public static void NamedDivideByZero()
+ {
+ Assert.Throws<OverflowException>(() => TimeSpan.FromDays(1).Divide(0));
+ Assert.Throws<OverflowException>(() => TimeSpan.FromDays(-1).Divide(0));
+ Assert.Throws<OverflowException>(() => TimeSpan.Zero.Divide(0));
+ Assert.Equal(double.PositiveInfinity, TimeSpan.FromDays(1).Divide(TimeSpan.Zero));
+ Assert.Equal(double.NegativeInfinity, TimeSpan.FromDays(-1).Divide(TimeSpan.Zero));
+ Assert.True(double.IsNaN(TimeSpan.Zero.Divide(TimeSpan.Zero)));
+ }
+
+ [Fact]
+ public static void NamedNaNDivision()
+ {
+ AssertExtensions.Throws<ArgumentException>("divisor", () => TimeSpan.FromDays(1).Divide(double.NaN));
+ }
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2] };
+ }
+
+ yield return new object[] { " 12:24:02 ", 5, 8, null, new TimeSpan(0, 12, 24, 2, 0) };
+ yield return new object[] { " 12:24:02 ", 6, 7, null, new TimeSpan(0, 2, 24, 2, 0) };
+ yield return new object[] { " 12:24:02 ", 6, 6, null, new TimeSpan(0, 2, 24, 0, 0) };
+ yield return new object[] { "12:24:02.01", 0, 8, CultureInfo.InvariantCulture, new TimeSpan(0, 12, 24, 2, 0) };
+ yield return new object[] { "1:1:1.00000001", 0, 7, CultureInfo.InvariantCulture, new TimeSpan(1, 1, 1) };
+ yield return new object[] { "1:1:.00000001", 0, 6, CultureInfo.InvariantCulture, new TimeSpan(36600000000) };
+ yield return new object[] { "24:00:00", 1, 7, null, new TimeSpan(4, 0, 0) };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span(string inputString, int offset, int count, IFormatProvider provider, TimeSpan expected)
+ {
+ ReadOnlySpan<char> input = inputString.AsSpan(offset, count);
+ TimeSpan result;
+
+ // Default provider.
+ if (provider == null)
+ {
+ Assert.True(TimeSpan.TryParse(input, out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, TimeSpan.Parse(input, provider));
+ Assert.True(TimeSpan.TryParse(input, provider, out result));
+ Assert.Equal(expected, result);
+
+ // Also negate
+ if (!char.IsWhiteSpace(input[0]))
+ {
+ input = ("-" + inputString.Substring(offset, count)).AsSpan();
+ expected = -expected;
+
+ Assert.Equal(expected, TimeSpan.Parse(input, provider));
+ Assert.True(TimeSpan.TryParse(input, provider, out result));
+ Assert.Equal(expected, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string inputString, IFormatProvider provider, Type exceptionType)
+ {
+ if (inputString != null)
+ {
+ Assert.Throws(exceptionType, () => TimeSpan.Parse(inputString.AsSpan(), provider));
+ Assert.False(TimeSpan.TryParse(inputString.AsSpan(), provider, out TimeSpan result));
+ Assert.Equal(TimeSpan.Zero, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ParseExact_Valid_TestData))]
+ public static void ParseExact_Span_Valid(string inputString, string format, TimeSpan expected)
+ {
+ ReadOnlySpan<char> input = inputString.AsSpan();
+
+ TimeSpan result;
+ Assert.Equal(expected, TimeSpan.ParseExact(input, format, new CultureInfo("en-US")));
+ Assert.Equal(expected, TimeSpan.ParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.None));
+ Assert.Equal(expected, TimeSpan.ParseExact(input, new[] { format }, new CultureInfo("en-US")));
+ Assert.Equal(expected, TimeSpan.ParseExact(input, new[] { format }, new CultureInfo("en-US"), TimeSpanStyles.None));
+
+ Assert.True(TimeSpan.TryParseExact(input, format, new CultureInfo("en-US"), out result));
+ Assert.Equal(expected, result);
+
+ Assert.True(TimeSpan.TryParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
+ Assert.Equal(expected, result);
+
+ Assert.True(TimeSpan.TryParseExact(input, new[] { format }, new CultureInfo("en-US"), out result));
+ Assert.Equal(expected, result);
+
+ Assert.True(TimeSpan.TryParseExact(input, new[] { format }, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
+ Assert.Equal(expected, result);
+
+ if (format != "c" && format != "t" && format != "T" && format != "g" && format != "G")
+ {
+ // TimeSpanStyles is interpreted only for custom formats
+ Assert.Equal(expected.Negate(), TimeSpan.ParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.AssumeNegative));
+
+ Assert.True(TimeSpan.TryParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.AssumeNegative, out result));
+ Assert.Equal(expected.Negate(), result);
+ }
+ else
+ {
+ // Inputs that can be parsed in standard formats with ParseExact should also be parsable with Parse
+ Assert.Equal(expected, TimeSpan.Parse(input, CultureInfo.InvariantCulture));
+
+ Assert.True(TimeSpan.TryParse(input, CultureInfo.InvariantCulture, out result));
+ Assert.Equal(expected, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ParseExact_Invalid_TestData))]
+ public static void ParseExactTest_Span_Invalid(string inputString, string format, Type exceptionType)
+ {
+ if (inputString != null && format != null)
+ {
+ Assert.Throws(exceptionType, () => TimeSpan.ParseExact(inputString.AsSpan(), format, new CultureInfo("en-US")));
+
+ TimeSpan result;
+ Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), format, new CultureInfo("en-US"), out result));
+ Assert.Equal(TimeSpan.Zero, result);
+
+ Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), format, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
+ Assert.Equal(TimeSpan.Zero, result);
+
+ Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), new[] { format }, new CultureInfo("en-US"), out result));
+ Assert.Equal(TimeSpan.Zero, result);
+
+ Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), new[] { format }, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
+ Assert.Equal(TimeSpan.Zero, result);
+ }
+ }
+
+ [Fact]
+ public static void ParseExactMultiple_Span_InvalidNullEmptyFormats()
+ {
+ TimeSpan result;
+
+ AssertExtensions.Throws<ArgumentNullException>("formats", () => TimeSpan.ParseExact("12:34:56".AsSpan(), (string[])null, null));
+ Assert.False(TimeSpan.TryParseExact("12:34:56".AsSpan(), (string[])null, null, out result));
+
+ Assert.Throws<FormatException>(() => TimeSpan.ParseExact("12:34:56".AsSpan(), new string[0], null));
+ Assert.False(TimeSpan.TryParseExact("12:34:56".AsSpan(), new string[0], null, out result));
+ }
+
+ [Theory]
+ [MemberData(nameof(ParseExact_InvalidStyles_TestData))]
+ public void ParseExact_InvalidStylesSpan_ThrowsArgumentException(TimeSpanStyles styles)
+ {
+ TimeSpan result;
+
+ string inputString = "00:00:00";
+ AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles));
+ AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), new string[] { "s" }, new CultureInfo("en-US"), styles));
+ AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.TryParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles, out result));
+ AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.TryParseExact(inputString.AsSpan(), new string[] { "s" }, new CultureInfo("en-US"), styles, out result));
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat_Valid(TimeSpan input, string format, CultureInfo info, string expected)
+ {
+ int charsWritten;
+ Span<char> dst;
+
+ dst = new char[expected.Length - 1];
+ Assert.False(input.TryFormat(dst, out charsWritten, format, info));
+ Assert.Equal(0, charsWritten);
+
+ dst = new char[expected.Length];
+ Assert.True(input.TryFormat(dst, out charsWritten, format, info));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(dst));
+
+ dst = new char[expected.Length + 1];
+ Assert.True(input.TryFormat(dst, out charsWritten, format, info));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(dst.Slice(0, dst.Length - 1)));
+ Assert.Equal(0, dst[dst.Length - 1]);
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_InvalidFormat_TestData))]
+ public void TryFormat_InvalidFormat_ThrowsFormatException(string invalidFormat)
+ {
+ char[] dst = new char[1];
+ Assert.Throws<FormatException>(() => new TimeSpan().TryFormat(dst.AsSpan(), out int charsWritten, invalidFormat, null));
+ }
+
+ [Fact]
+ public static void ConvertToTimeSpanPrecisionTest()
+ {
+ Assert.Equal(12345, TimeSpan.FromMilliseconds(1.23456).Ticks);
+ Assert.Equal(12345, TimeSpan.FromMilliseconds(1.234567).Ticks);
+
+ Assert.Equal(12345600, TimeSpan.FromSeconds(1.23456).Ticks);
+
+ Assert.Equal(1.23456 * 60 * 10_000_000, TimeSpan.FromMinutes(1.23456).Ticks);
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class TimeSpanTests
- {
- public static IEnumerable<object[]> MultiplicationTestData()
- {
- yield return new object[] {new TimeSpan(2, 30, 0), 2.0, new TimeSpan(5, 0, 0)};
- yield return new object[] {new TimeSpan(14, 2, 30, 0), 192.0, TimeSpan.FromDays(2708)};
- yield return new object[] {TimeSpan.FromDays(366), Math.PI, new TimeSpan(993446995288779)};
- yield return new object[] {TimeSpan.FromDays(366), -Math.E, new TimeSpan(-859585952922633)};
- yield return new object[] {TimeSpan.FromDays(29.530587981), 13.0, TimeSpan.FromDays(29.530587981 * 13.0) };
- yield return new object[] {TimeSpan.FromDays(-29.530587981), -12.0, TimeSpan.FromDays(-29.530587981 * -12.0) };
- yield return new object[] {TimeSpan.FromDays(-29.530587981), 0.0, TimeSpan.Zero};
- yield return new object[] {TimeSpan.MaxValue, 0.5, TimeSpan.FromTicks((long)(long.MaxValue * 0.5))};
- }
-
- // ParseDifferentLengthFractionWithLeadingZerosData mainly testing the behavior we have fixed in net core
- // which is the way we normalize the parsed fraction and possibly rounding it.
- public static IEnumerable<object[]> ParseDifferentLengthFractionWithLeadingZerosData()
- {
- yield return new object[] {"00:00:00.00000001", new TimeSpan(0)};
- yield return new object[] {"00:00:00.00000005", new TimeSpan(1)};
- yield return new object[] {"00:00:00.09999999", new TimeSpan(1_000_000)};
- yield return new object[] {"00:00:00.0268435455", new TimeSpan(268435)};
- yield return new object[] {"00:00:00.01", new TimeSpan(1_00_000)};
- yield return new object[] {"0:00:00.01000000", new TimeSpan(100_000)};
- yield return new object[] {"0:00:00.010000000", new TimeSpan(100_000)};
- yield return new object[] {"0:00:00.0123456", new TimeSpan(123456)};
- yield return new object[] {"0:00:00.00123456", new TimeSpan(12346)};
- yield return new object[] {"0:00:00.00000098", new TimeSpan(10)};
- yield return new object[] {"0:00:00.00000099", new TimeSpan(10)};
- }
-
- [Theory, MemberData(nameof(ParseDifferentLengthFractionWithLeadingZerosData))]
- public static void Multiplication(string input, TimeSpan expected)
- {
- Assert.Equal(expected, TimeSpan.Parse(input, CultureInfo.InvariantCulture));
- Assert.Equal(expected, TimeSpan.ParseExact(input, "g", CultureInfo.InvariantCulture));
- }
-
- [Theory, MemberData(nameof(MultiplicationTestData))]
- public static void Multiplication(TimeSpan timeSpan, double factor, TimeSpan expected)
- {
- Assert.Equal(expected, timeSpan * factor);
- Assert.Equal(expected, factor * timeSpan);
- }
-
- [Fact]
- public static void OverflowingMultiplication()
- {
- Assert.Throws<OverflowException>(() => TimeSpan.MaxValue * 1.000000001);
- Assert.Throws<OverflowException>(() => -1.000000001 * TimeSpan.MaxValue);
- }
-
- [Fact]
- public static void NaNMultiplication()
- {
- AssertExtensions.Throws<ArgumentException>("factor", () => TimeSpan.FromDays(1) * double.NaN);
- AssertExtensions.Throws<ArgumentException>("factor", () => double.NaN * TimeSpan.FromDays(1));
- }
-
- [Theory, MemberData(nameof(MultiplicationTestData))]
- public static void Division(TimeSpan timeSpan, double factor, TimeSpan expected)
- {
- Assert.Equal(factor, expected / timeSpan, 14);
- double divisor = 1.0 / factor;
- Assert.Equal(expected, timeSpan / divisor);
- }
-
- [Fact]
- public static void DivideByZero()
- {
- Assert.Throws<OverflowException>(() => TimeSpan.FromDays(1) / 0);
- Assert.Throws<OverflowException>(() => TimeSpan.FromDays(-1) / 0);
- Assert.Throws<OverflowException>(() => TimeSpan.Zero / 0);
- Assert.Equal(double.PositiveInfinity, TimeSpan.FromDays(1) / TimeSpan.Zero);
- Assert.Equal(double.NegativeInfinity, TimeSpan.FromDays(-1) / TimeSpan.Zero);
- Assert.True(double.IsNaN(TimeSpan.Zero / TimeSpan.Zero));
- }
-
- [Fact]
- public static void NaNDivision()
- {
- AssertExtensions.Throws<ArgumentException>("divisor", () => TimeSpan.FromDays(1) / double.NaN);
- }
-
- [Theory, MemberData(nameof(MultiplicationTestData))]
- public static void NamedMultiplication(TimeSpan timeSpan, double factor, TimeSpan expected)
- {
- Assert.Equal(expected, timeSpan.Multiply(factor));
- }
-
- [Fact]
- public static void NamedOverflowingMultiplication()
- {
- Assert.Throws<OverflowException>(() => TimeSpan.MaxValue.Multiply(1.000000001));
- }
-
- [Fact]
- public static void NamedNaNMultiplication()
- {
- AssertExtensions.Throws<ArgumentException>("factor", () => TimeSpan.FromDays(1).Multiply(double.NaN));
- }
-
- [Theory, MemberData(nameof(MultiplicationTestData))]
- public static void NamedDivision(TimeSpan timeSpan, double factor, TimeSpan expected)
- {
- Assert.Equal(factor, expected.Divide(timeSpan), 14);
- double divisor = 1.0 / factor;
- Assert.Equal(expected, timeSpan.Divide(divisor));
- }
-
- [Fact]
- public static void NamedDivideByZero()
- {
- Assert.Throws<OverflowException>(() => TimeSpan.FromDays(1).Divide(0));
- Assert.Throws<OverflowException>(() => TimeSpan.FromDays(-1).Divide(0));
- Assert.Throws<OverflowException>(() => TimeSpan.Zero.Divide(0));
- Assert.Equal(double.PositiveInfinity, TimeSpan.FromDays(1).Divide(TimeSpan.Zero));
- Assert.Equal(double.NegativeInfinity, TimeSpan.FromDays(-1).Divide(TimeSpan.Zero));
- Assert.True(double.IsNaN(TimeSpan.Zero.Divide(TimeSpan.Zero)));
- }
-
- [Fact]
- public static void NamedNaNDivision()
- {
- AssertExtensions.Throws<ArgumentException>("divisor", () => TimeSpan.FromDays(1).Divide(double.NaN));
- }
-
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2] };
- }
-
- yield return new object[] { " 12:24:02 ", 5, 8, null, new TimeSpan(0, 12, 24, 2, 0) };
- yield return new object[] { " 12:24:02 ", 6, 7, null, new TimeSpan(0, 2, 24, 2, 0) };
- yield return new object[] { " 12:24:02 ", 6, 6, null, new TimeSpan(0, 2, 24, 0, 0) };
- yield return new object[] { "12:24:02.01", 0, 8, CultureInfo.InvariantCulture, new TimeSpan(0, 12, 24, 2, 0) };
- yield return new object[] { "1:1:1.00000001", 0, 7, CultureInfo.InvariantCulture, new TimeSpan(1, 1, 1) };
- yield return new object[] { "1:1:.00000001", 0, 6, CultureInfo.InvariantCulture, new TimeSpan(36600000000) };
- yield return new object[] { "24:00:00", 1, 7, null, new TimeSpan(4, 0, 0) };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span(string inputString, int offset, int count, IFormatProvider provider, TimeSpan expected)
- {
- ReadOnlySpan<char> input = inputString.AsSpan(offset, count);
- TimeSpan result;
-
- // Default provider.
- if (provider == null)
- {
- Assert.True(TimeSpan.TryParse(input, out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, TimeSpan.Parse(input, provider));
- Assert.True(TimeSpan.TryParse(input, provider, out result));
- Assert.Equal(expected, result);
-
- // Also negate
- if (!char.IsWhiteSpace(input[0]))
- {
- input = ("-" + inputString.Substring(offset, count)).AsSpan();
- expected = -expected;
-
- Assert.Equal(expected, TimeSpan.Parse(input, provider));
- Assert.True(TimeSpan.TryParse(input, provider, out result));
- Assert.Equal(expected, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string inputString, IFormatProvider provider, Type exceptionType)
- {
- if (inputString != null)
- {
- Assert.Throws(exceptionType, () => TimeSpan.Parse(inputString.AsSpan(), provider));
- Assert.False(TimeSpan.TryParse(inputString.AsSpan(), provider, out TimeSpan result));
- Assert.Equal(TimeSpan.Zero, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ParseExact_Valid_TestData))]
- public static void ParseExact_Span_Valid(string inputString, string format, TimeSpan expected)
- {
- ReadOnlySpan<char> input = inputString.AsSpan();
-
- TimeSpan result;
- Assert.Equal(expected, TimeSpan.ParseExact(input, format, new CultureInfo("en-US")));
- Assert.Equal(expected, TimeSpan.ParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.None));
- Assert.Equal(expected, TimeSpan.ParseExact(input, new[] { format }, new CultureInfo("en-US")));
- Assert.Equal(expected, TimeSpan.ParseExact(input, new[] { format }, new CultureInfo("en-US"), TimeSpanStyles.None));
-
- Assert.True(TimeSpan.TryParseExact(input, format, new CultureInfo("en-US"), out result));
- Assert.Equal(expected, result);
-
- Assert.True(TimeSpan.TryParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
- Assert.Equal(expected, result);
-
- Assert.True(TimeSpan.TryParseExact(input, new[] { format }, new CultureInfo("en-US"), out result));
- Assert.Equal(expected, result);
-
- Assert.True(TimeSpan.TryParseExact(input, new[] { format }, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
- Assert.Equal(expected, result);
-
- if (format != "c" && format != "t" && format != "T" && format != "g" && format != "G")
- {
- // TimeSpanStyles is interpreted only for custom formats
- Assert.Equal(expected.Negate(), TimeSpan.ParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.AssumeNegative));
-
- Assert.True(TimeSpan.TryParseExact(input, format, new CultureInfo("en-US"), TimeSpanStyles.AssumeNegative, out result));
- Assert.Equal(expected.Negate(), result);
- }
- else
- {
- // Inputs that can be parsed in standard formats with ParseExact should also be parsable with Parse
- Assert.Equal(expected, TimeSpan.Parse(input, CultureInfo.InvariantCulture));
-
- Assert.True(TimeSpan.TryParse(input, CultureInfo.InvariantCulture, out result));
- Assert.Equal(expected, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ParseExact_Invalid_TestData))]
- public static void ParseExactTest_Span_Invalid(string inputString, string format, Type exceptionType)
- {
- if (inputString != null && format != null)
- {
- Assert.Throws(exceptionType, () => TimeSpan.ParseExact(inputString.AsSpan(), format, new CultureInfo("en-US")));
-
- TimeSpan result;
- Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), format, new CultureInfo("en-US"), out result));
- Assert.Equal(TimeSpan.Zero, result);
-
- Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), format, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
- Assert.Equal(TimeSpan.Zero, result);
-
- Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), new[] { format }, new CultureInfo("en-US"), out result));
- Assert.Equal(TimeSpan.Zero, result);
-
- Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), new[] { format }, new CultureInfo("en-US"), TimeSpanStyles.None, out result));
- Assert.Equal(TimeSpan.Zero, result);
- }
- }
-
- [Fact]
- public static void ParseExactMultiple_Span_InvalidNullEmptyFormats()
- {
- TimeSpan result;
-
- AssertExtensions.Throws<ArgumentNullException>("formats", () => TimeSpan.ParseExact("12:34:56".AsSpan(), (string[])null, null));
- Assert.False(TimeSpan.TryParseExact("12:34:56".AsSpan(), (string[])null, null, out result));
-
- Assert.Throws<FormatException>(() => TimeSpan.ParseExact("12:34:56".AsSpan(), new string[0], null));
- Assert.False(TimeSpan.TryParseExact("12:34:56".AsSpan(), new string[0], null, out result));
- }
-
- [Theory]
- [MemberData(nameof(ParseExact_InvalidStyles_TestData))]
- public void ParseExact_InvalidStylesSpan_ThrowsArgumentException(TimeSpanStyles styles)
- {
- TimeSpan result;
-
- string inputString = "00:00:00";
- AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles));
- AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), new string[] { "s" }, new CultureInfo("en-US"), styles));
- AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.TryParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles, out result));
- AssertExtensions.Throws<ArgumentException>("styles", () => TimeSpan.TryParseExact(inputString.AsSpan(), new string[] { "s" }, new CultureInfo("en-US"), styles, out result));
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat_Valid(TimeSpan input, string format, CultureInfo info, string expected)
- {
- int charsWritten;
- Span<char> dst;
-
- dst = new char[expected.Length - 1];
- Assert.False(input.TryFormat(dst, out charsWritten, format, info));
- Assert.Equal(0, charsWritten);
-
- dst = new char[expected.Length];
- Assert.True(input.TryFormat(dst, out charsWritten, format, info));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(dst));
-
- dst = new char[expected.Length + 1];
- Assert.True(input.TryFormat(dst, out charsWritten, format, info));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(dst.Slice(0, dst.Length - 1)));
- Assert.Equal(0, dst[dst.Length - 1]);
- }
-
- [Theory]
- [MemberData(nameof(ToString_InvalidFormat_TestData))]
- public void TryFormat_InvalidFormat_ThrowsFormatException(string invalidFormat)
- {
- char[] dst = new char[1];
- Assert.Throws<FormatException>(() => new TimeSpan().TryFormat(dst.AsSpan(), out int charsWritten, invalidFormat, null));
- }
-
- [Fact]
- public static void ConvertToTimeSpanPrecisionTest()
- {
- Assert.Equal(12345, TimeSpan.FromMilliseconds(1.23456).Ticks);
- Assert.Equal(12345, TimeSpan.FromMilliseconds(1.234567).Ticks);
-
- Assert.Equal(12345600, TimeSpan.FromSeconds(1.23456).Ticks);
-
- Assert.Equal(1.23456 * 60 * 10_000_000, TimeSpan.FromMinutes(1.23456).Ticks);
- }
- }
-}
namespace System.Tests.Types
{
- public abstract partial class TypePropertyTestBase
+ public abstract class TypePropertyTestBase
{
public abstract Type CreateType();
{
Assert.Equal(UnderlyingSystemType, CreateType().UnderlyingSystemType);
}
+
+ [Fact]
+ public void IsGenericMethodParameter_Get_ReturnsExpected()
+ {
+ Assert.Equal(IsGenericMethodParameter, CreateType().IsGenericMethodParameter);
+ }
+
+ [Fact]
+ public void IsGenericTypeParameter_Get_ReturnsExpected()
+ {
+ Assert.Equal(IsGenericTypeParameter, CreateType().IsGenericTypeParameter);
+ }
+
+ [Fact]
+ public void IsSignatureType_Get_ReturnsExpected()
+ {
+ Assert.Equal(IsSignatureType, CreateType().IsSignatureType);
+ }
+
+ [Fact]
+ public void IsSZArray_Get_ReturnsExpected()
+ {
+ Assert.Equal(IsSZArray, CreateType().IsSZArray);
+ }
+
+ [Fact]
+ public void IsTypeDefinition_Get_ReturnsExpected()
+ {
+ Assert.Equal(IsTypeDefinition, CreateType().IsTypeDefinition);
+ }
+
+ [Fact]
+ public void IsVariableBoundArray_Get_ReturnsExpected()
+ {
+ Assert.Equal(IsVariableBoundArray, CreateType().IsVariableBoundArray);
+ }
}
public abstract class ArrayTypeTestBase : TypePropertyTestBase
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Reflection;
-using Xunit;
-
-namespace System.Tests.Types
-{
- public abstract partial class TypePropertyTestBase
- {
- [Fact]
- public void IsGenericMethodParameter_Get_ReturnsExpected()
- {
- Assert.Equal(IsGenericMethodParameter, CreateType().IsGenericMethodParameter);
- }
-
- [Fact]
- public void IsGenericTypeParameter_Get_ReturnsExpected()
- {
- Assert.Equal(IsGenericTypeParameter, CreateType().IsGenericTypeParameter);
- }
-
- [Fact]
- public void IsSignatureType_Get_ReturnsExpected()
- {
- Assert.Equal(IsSignatureType, CreateType().IsSignatureType);
- }
-
- [Fact]
- public void IsSZArray_Get_ReturnsExpected()
- {
- Assert.Equal(IsSZArray, CreateType().IsSZArray);
- }
-
- [Fact]
- public void IsTypeDefinition_Get_ReturnsExpected()
- {
- Assert.Equal(IsTypeDefinition, CreateType().IsTypeDefinition);
- }
-
- [Fact]
- public void IsVariableBoundArray_Get_ReturnsExpected()
- {
- Assert.Equal(IsVariableBoundArray, CreateType().IsVariableBoundArray);
- }
- }
-}
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
{
public partial class TypeTests
{
+ private static readonly IList<Type> NonArrayBaseTypes;
+
+ static TypeTests()
+ {
+ NonArrayBaseTypes = new List<Type>()
+ {
+ typeof(int),
+ typeof(void),
+ typeof(int*),
+ typeof(Outside),
+ typeof(Outside<int>),
+ typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0],
+ new object().GetType().GetType()
+ };
+
+ if (PlatformDetection.IsWindows)
+ {
+ NonArrayBaseTypes.Add(Type.GetTypeFromCLSID(default(Guid)));
+ }
+ }
+
[Fact]
public void FilterName_Get_ReturnsExpected()
{
Assert.Throws<PlatformNotSupportedException>(() => Type.ReflectionOnlyGetType("", true, true));
Assert.Throws<PlatformNotSupportedException>(() => Type.ReflectionOnlyGetType("System.Tests.TypeTests", false, true));
}
+
+ [Fact]
+ public void IsSZArray_FalseForNonArrayTypes()
+ {
+ foreach (Type type in NonArrayBaseTypes)
+ {
+ Assert.False(type.IsSZArray);
+ }
+ }
+
+ [Fact]
+ public void IsSZArray_TrueForSZArrayTypes()
+ {
+ foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType()))
+ {
+ Assert.True(type.IsSZArray);
+ }
+ }
+
+ [Fact]
+ public void IsSZArray_FalseForVariableBoundArrayTypes()
+ {
+ foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(1)))
+ {
+ Assert.False(type.IsSZArray);
+ }
+
+ foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(2)))
+ {
+ Assert.False(type.IsSZArray);
+ }
+ }
+
+ [Fact]
+ public void IsSZArray_FalseForNonArrayByRefType()
+ {
+ Assert.False(typeof(int).MakeByRefType().IsSZArray);
+ }
+
+ [Fact]
+ public void IsSZArray_FalseForByRefSZArrayType()
+ {
+ Assert.False(typeof(int[]).MakeByRefType().IsSZArray);
+ }
+
+
+ [Fact]
+ public void IsSZArray_FalseForByRefVariableArrayType()
+ {
+ Assert.False(typeof(int[,]).MakeByRefType().IsSZArray);
+ }
+
+ [Fact]
+ public void IsVariableBoundArray_FalseForNonArrayTypes()
+ {
+ foreach (Type type in NonArrayBaseTypes)
+ {
+ Assert.False(type.IsVariableBoundArray);
+ }
+ }
+
+ [Fact]
+ public void IsVariableBoundArray_FalseForSZArrayTypes()
+ {
+ foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType()))
+ {
+ Assert.False(type.IsVariableBoundArray);
+ }
+ }
+
+ [Fact]
+ public void IsVariableBoundArray_TrueForVariableBoundArrayTypes()
+ {
+ foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(1)))
+ {
+ Assert.True(type.IsVariableBoundArray);
+ }
+
+ foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(2)))
+ {
+ Assert.True(type.IsVariableBoundArray);
+ }
+ }
+
+ [Fact]
+ public void IsVariableBoundArray_FalseForNonArrayByRefType()
+ {
+ Assert.False(typeof(int).MakeByRefType().IsVariableBoundArray);
+ }
+
+ [Fact]
+ public void IsVariableBoundArray_FalseForByRefSZArrayType()
+ {
+ Assert.False(typeof(int[]).MakeByRefType().IsVariableBoundArray);
+ }
+
+
+ [Fact]
+ public void IsVariableBoundArray_FalseForByRefVariableArrayType()
+ {
+ Assert.False(typeof(int[,]).MakeByRefType().IsVariableBoundArray);
+ }
+
+ [Theory]
+ [MemberData(nameof(DefinedTypes))]
+ public void IsTypeDefinition_True(Type type)
+ {
+ Assert.True(type.IsTypeDefinition);
+ }
+
+ [Theory]
+ [MemberData(nameof(NotDefinedTypes))]
+ public void IsTypeDefinition_False(Type type)
+ {
+ Assert.False(type.IsTypeDefinition);
+ }
+
+ // In the unlikely event we ever add new values to the CorElementType enumeration, CoreCLR will probably miss it because of the way IsTypeDefinition
+ // works. It's likely that such a type will live in the core assembly so to improve our chances of catching this situation, test IsTypeDefinition
+ // on every type exposed out of that assembly.
+ //
+ // Skipping this on .NET Native because:
+ // - We really don't want to opt in all the metadata in System.Private.CoreLib
+ // - The .NET Native implementation of IsTypeDefinition is not the one that works by enumerating selected values off CorElementType.
+ // It has much less need of a test like this.
+ [Fact]
+ public void IsTypeDefinition_AllDefinedTypesInCoreAssembly()
+ {
+ foreach (Type type in typeof(object).Assembly.DefinedTypes)
+ {
+ Assert.True(type.IsTypeDefinition, "IsTypeDefinition expected to be true for type " + type);
+ }
+ }
+
+ public static IEnumerable<object[]> DefinedTypes
+ {
+ get
+ {
+ yield return new object[] { typeof(void) };
+ yield return new object[] { typeof(int) };
+ yield return new object[] { typeof(Outside) };
+ yield return new object[] { typeof(Outside.Inside) };
+ yield return new object[] { typeof(Outside<>) };
+ yield return new object[] { typeof(IEnumerable<>) };
+ yield return new object[] { 3.GetType().GetType() }; // This yields a reflection-blocked type on .NET Native - which is implemented separately
+
+ if (PlatformDetection.IsWindows)
+ yield return new object[] { Type.GetTypeFromCLSID(default(Guid)) };
+ }
+ }
+
+ public static IEnumerable<object[]> NotDefinedTypes
+ {
+ get
+ {
+ Type theT = typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0];
+
+ yield return new object[] { typeof(int[]) };
+ yield return new object[] { theT.MakeArrayType(1) }; // Using an open type as element type gets around .NET Native nonsupport of rank-1 multidim arrays
+ yield return new object[] { typeof(int[,]) };
+
+ yield return new object[] { typeof(int).MakeByRefType() };
+
+ yield return new object[] { typeof(int).MakePointerType() };
+
+ yield return new object[] { typeof(Outside<int>) };
+ yield return new object[] { typeof(Outside<int>.Inside<int>) };
+
+ yield return new object[] { theT };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(IsByRefLikeTestData))]
+ public static void TestIsByRefLike(Type type, bool expected)
+ {
+ Assert.Equal(expected, type.IsByRefLike);
+ }
+
+ public static IEnumerable<object[]> IsByRefLikeTestData
+ {
+ get
+ {
+ Type theT = typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0];
+
+ yield return new object[] { typeof(ArgIterator), true };
+ yield return new object[] { typeof(ByRefLikeStruct), true };
+ yield return new object[] { typeof(RegularStruct), false };
+ yield return new object[] { typeof(RuntimeArgumentHandle), true };
+ yield return new object[] { typeof(Span<>), true };
+ yield return new object[] { typeof(Span<>).MakeGenericType(theT), true };
+ yield return new object[] { typeof(Span<int>), true };
+ yield return new object[] { typeof(Span<int>).MakeByRefType(), false };
+ yield return new object[] { typeof(Span<int>).MakePointerType(), false };
+ yield return new object[] { typeof(TypedReference), true };
+ yield return new object[] { theT, false };
+ yield return new object[] { typeof(int[]), false };
+ yield return new object[] { typeof(int[,]), false };
+ yield return new object[] { typeof(object), false };
+ if (PlatformDetection.IsWindows) // GetTypeFromCLSID is Windows only
+ {
+ yield return new object[] { Type.GetTypeFromCLSID(default(Guid)), false };
+ }
+ }
+ }
+
+ private ref struct ByRefLikeStruct
+ {
+ public ByRefLikeStruct(int dummy)
+ {
+ S = default(Span<int>);
+ }
+
+ public Span<int> S;
+ }
+
+ private struct RegularStruct
+ {
+ }
+
+ [Theory]
+ [MemberData(nameof(IsGenericParameterTestData))]
+ public static void TestIsGenericParameter(Type type, bool isGenericParameter, bool isGenericTypeParameter, bool isGenericMethodParameter)
+ {
+ Assert.Equal(isGenericParameter, type.IsGenericParameter);
+ Assert.Equal(isGenericTypeParameter, type.IsGenericTypeParameter);
+ Assert.Equal(isGenericMethodParameter, type.IsGenericMethodParameter);
+ }
+
+ public static IEnumerable<object[]> IsGenericParameterTestData
+ {
+ get
+ {
+ yield return new object[] { typeof(void), false, false, false };
+ yield return new object[] { typeof(int), false, false, false };
+ yield return new object[] { typeof(int[]), false, false, false };
+ yield return new object[] { typeof(int).MakeArrayType(1), false, false, false };
+ yield return new object[] { typeof(int[,]), false, false, false };
+ yield return new object[] { typeof(int).MakeByRefType(), false, false, false };
+ yield return new object[] { typeof(int).MakePointerType(), false, false, false };
+ yield return new object[] { typeof(DummyGenericClassForTypeTests<>), false, false, false };
+ yield return new object[] { typeof(DummyGenericClassForTypeTests<int>), false, false, false };
+ if (PlatformDetection.IsWindows) // GetTypeFromCLSID is Windows only
+ {
+ yield return new object[] { Type.GetTypeFromCLSID(default(Guid)), false, false, false };
+ }
+
+ Type theT = typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0];
+ yield return new object[] { theT, true, true, false };
+
+ Type theM = typeof(TypeTests).GetMethod(nameof(GenericMethod), BindingFlags.NonPublic | BindingFlags.Static).GetGenericArguments()[0];
+ yield return new object[] { theM, true, false, true };
+ }
+ }
+
+ private static void GenericMethod<M>() { }
}
public class TypeTestsExtended {
public interface GenericInterface<T> { }
public interface GenericInterface<T, U> { }
}
+
+internal class DummyGenericClassForTypeTests<T> { }
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using Xunit;
-
-namespace System.Tests
-{
- public class TypeTestsNetcore
- {
- private static readonly IList<Type> NonArrayBaseTypes;
-
- static TypeTestsNetcore()
- {
- NonArrayBaseTypes = new List<Type>()
- {
- typeof(int),
- typeof(void),
- typeof(int*),
- typeof(Outside),
- typeof(Outside<int>),
- typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0],
- new object().GetType().GetType()
- };
-
- if (PlatformDetection.IsWindows)
- {
- NonArrayBaseTypes.Add(Type.GetTypeFromCLSID(default(Guid)));
- }
- }
-
- [Fact]
- public void IsSZArray_FalseForNonArrayTypes()
- {
- foreach (Type type in NonArrayBaseTypes)
- {
- Assert.False(type.IsSZArray);
- }
- }
-
- [Fact]
- public void IsSZArray_TrueForSZArrayTypes()
- {
- foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType()))
- {
- Assert.True(type.IsSZArray);
- }
- }
-
- [Fact]
- public void IsSZArray_FalseForVariableBoundArrayTypes()
- {
- foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(1)))
- {
- Assert.False(type.IsSZArray);
- }
-
- foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(2)))
- {
- Assert.False(type.IsSZArray);
- }
- }
-
- [Fact]
- public void IsSZArray_FalseForNonArrayByRefType()
- {
- Assert.False(typeof(int).MakeByRefType().IsSZArray);
- }
-
- [Fact]
- public void IsSZArray_FalseForByRefSZArrayType()
- {
- Assert.False(typeof(int[]).MakeByRefType().IsSZArray);
- }
-
-
- [Fact]
- public void IsSZArray_FalseForByRefVariableArrayType()
- {
- Assert.False(typeof(int[,]).MakeByRefType().IsSZArray);
- }
-
- [Fact]
- public void IsVariableBoundArray_FalseForNonArrayTypes()
- {
- foreach (Type type in NonArrayBaseTypes)
- {
- Assert.False(type.IsVariableBoundArray);
- }
- }
-
- [Fact]
- public void IsVariableBoundArray_FalseForSZArrayTypes()
- {
- foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType()))
- {
- Assert.False(type.IsVariableBoundArray);
- }
- }
-
- [Fact]
- public void IsVariableBoundArray_TrueForVariableBoundArrayTypes()
- {
- foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(1)))
- {
- Assert.True(type.IsVariableBoundArray);
- }
-
- foreach (Type type in NonArrayBaseTypes.Select(nonArrayBaseType => nonArrayBaseType.MakeArrayType(2)))
- {
- Assert.True(type.IsVariableBoundArray);
- }
- }
-
- [Fact]
- public void IsVariableBoundArray_FalseForNonArrayByRefType()
- {
- Assert.False(typeof(int).MakeByRefType().IsVariableBoundArray);
- }
-
- [Fact]
- public void IsVariableBoundArray_FalseForByRefSZArrayType()
- {
- Assert.False(typeof(int[]).MakeByRefType().IsVariableBoundArray);
- }
-
-
- [Fact]
- public void IsVariableBoundArray_FalseForByRefVariableArrayType()
- {
- Assert.False(typeof(int[,]).MakeByRefType().IsVariableBoundArray);
- }
-
- [Theory]
- [MemberData(nameof(DefinedTypes))]
- public void IsTypeDefinition_True(Type type)
- {
- Assert.True(type.IsTypeDefinition);
- }
-
- [Theory]
- [MemberData(nameof(NotDefinedTypes))]
- public void IsTypeDefinition_False(Type type)
- {
- Assert.False(type.IsTypeDefinition);
- }
-
- // In the unlikely event we ever add new values to the CorElementType enumeration, CoreCLR will probably miss it because of the way IsTypeDefinition
- // works. It's likely that such a type will live in the core assembly so to improve our chances of catching this situation, test IsTypeDefinition
- // on every type exposed out of that assembly.
- //
- // Skipping this on .NET Native because:
- // - We really don't want to opt in all the metadata in System.Private.CoreLib
- // - The .NET Native implementation of IsTypeDefinition is not the one that works by enumerating selected values off CorElementType.
- // It has much less need of a test like this.
- [Fact]
- public void IsTypeDefinition_AllDefinedTypesInCoreAssembly()
- {
- foreach (Type type in typeof(object).Assembly.DefinedTypes)
- {
- Assert.True(type.IsTypeDefinition, "IsTypeDefinition expected to be true for type " + type);
- }
- }
-
- public static IEnumerable<object[]> DefinedTypes
- {
- get
- {
- yield return new object[] { typeof(void) };
- yield return new object[] { typeof(int) };
- yield return new object[] { typeof(Outside) };
- yield return new object[] { typeof(Outside.Inside) };
- yield return new object[] { typeof(Outside<>) };
- yield return new object[] { typeof(IEnumerable<>) };
- yield return new object[] { 3.GetType().GetType() }; // This yields a reflection-blocked type on .NET Native - which is implemented separately
-
- if (PlatformDetection.IsWindows)
- yield return new object[] { Type.GetTypeFromCLSID(default(Guid)) };
- }
- }
-
- public static IEnumerable<object[]> NotDefinedTypes
- {
- get
- {
- Type theT = typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0];
-
- yield return new object[] { typeof(int[]) };
- yield return new object[] { theT.MakeArrayType(1) }; // Using an open type as element type gets around .NET Native nonsupport of rank-1 multidim arrays
- yield return new object[] { typeof(int[,]) };
-
- yield return new object[] { typeof(int).MakeByRefType() };
-
- yield return new object[] { typeof(int).MakePointerType() };
-
- yield return new object[] { typeof(Outside<int>) };
- yield return new object[] { typeof(Outside<int>.Inside<int>) };
-
- yield return new object[] { theT };
- }
- }
-
- [Theory]
- [MemberData(nameof(IsByRefLikeTestData))]
- public static void TestIsByRefLike(Type type, bool expected)
- {
- Assert.Equal(expected, type.IsByRefLike);
- }
-
- public static IEnumerable<object[]> IsByRefLikeTestData
- {
- get
- {
- Type theT = typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0];
-
- yield return new object[] { typeof(ArgIterator), true };
- yield return new object[] { typeof(ByRefLikeStruct), true };
- yield return new object[] { typeof(RegularStruct), false };
- yield return new object[] { typeof(RuntimeArgumentHandle), true };
- yield return new object[] { typeof(Span<>), true };
- yield return new object[] { typeof(Span<>).MakeGenericType(theT), true };
- yield return new object[] { typeof(Span<int>), true };
- yield return new object[] { typeof(Span<int>).MakeByRefType(), false };
- yield return new object[] { typeof(Span<int>).MakePointerType(), false };
- yield return new object[] { typeof(TypedReference), true };
- yield return new object[] { theT, false };
- yield return new object[] { typeof(int[]), false };
- yield return new object[] { typeof(int[,]), false };
- yield return new object[] { typeof(object), false };
- if (PlatformDetection.IsWindows) // GetTypeFromCLSID is Windows only
- {
- yield return new object[] { Type.GetTypeFromCLSID(default(Guid)), false };
- }
- }
- }
-
- private ref struct ByRefLikeStruct
- {
- public ByRefLikeStruct(int dummy)
- {
- S = default(Span<int>);
- }
-
- public Span<int> S;
- }
-
- private struct RegularStruct
- {
- }
-
- [Theory]
- [MemberData(nameof(IsGenericParameterTestData))]
- public static void TestIsGenericParameter(Type type, bool isGenericParameter, bool isGenericTypeParameter, bool isGenericMethodParameter)
- {
- Assert.Equal(isGenericParameter, type.IsGenericParameter);
- Assert.Equal(isGenericTypeParameter, type.IsGenericTypeParameter);
- Assert.Equal(isGenericMethodParameter, type.IsGenericMethodParameter);
- }
-
- public static IEnumerable<object[]> IsGenericParameterTestData
- {
- get
- {
- yield return new object[] { typeof(void), false, false, false };
- yield return new object[] { typeof(int), false, false, false };
- yield return new object[] { typeof(int[]), false, false, false };
- yield return new object[] { typeof(int).MakeArrayType(1), false, false, false };
- yield return new object[] { typeof(int[,]), false, false, false };
- yield return new object[] { typeof(int).MakeByRefType(), false, false, false };
- yield return new object[] { typeof(int).MakePointerType(), false, false, false };
- yield return new object[] { typeof(DummyGenericClassForTypeTestsNetcore<>), false, false, false };
- yield return new object[] { typeof(DummyGenericClassForTypeTestsNetcore<int>), false, false, false };
- if (PlatformDetection.IsWindows) // GetTypeFromCLSID is Windows only
- {
- yield return new object[] { Type.GetTypeFromCLSID(default(Guid)), false, false, false };
- }
-
- Type theT = typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0];
- yield return new object[] { theT, true, true, false };
-
- Type theM = typeof(TypeTestsNetcore).GetMethod(nameof(GenericMethod), BindingFlags.NonPublic | BindingFlags.Static).GetGenericArguments()[0];
- yield return new object[] { theM, true, false, true };
- }
- }
-
- private static void GenericMethod<M>() { }
- }
-}
-
-internal class DummyGenericClassForTypeTestsNetcore<T> { }
namespace System.Tests
{
- public partial class UInt16Tests
+ public class UInt16Tests
{
[Fact]
public static void Ctor_Empty()
AssertExtensions.Throws<ArgumentException>(paramName, () => ushort.Parse("1", style));
AssertExtensions.Throws<ArgumentException>(paramName, () => ushort.Parse("1", style, null));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (ushort)12 };
+ yield return new object[] { "123", 1, 2, NumberStyles.Integer, null, (ushort)23 };
+ yield return new object[] { "+123", 0, 2, NumberStyles.Integer, null, (ushort)1 };
+ yield return new object[] { "+123", 1, 3, NumberStyles.Integer, null, (ushort)123 };
+ yield return new object[] { "AJK", 0, 1, NumberStyles.HexNumber, new NumberFormatInfo(), (ushort)0XA };
+ yield return new object[] { "$1,000", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (ushort)1 };
+ yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (ushort)10 };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, ushort expected)
+ {
+ ushort result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(ushort.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, ushort.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(ushort.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ ushort result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(ushort.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0u, result);
+ }
+
+ Assert.Throws(exceptionType, () => ushort.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(ushort.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0u, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(ushort i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class UInt16Tests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (ushort)12 };
- yield return new object[] { "123", 1, 2, NumberStyles.Integer, null, (ushort)23 };
- yield return new object[] { "+123", 0, 2, NumberStyles.Integer, null, (ushort)1 };
- yield return new object[] { "+123", 1, 3, NumberStyles.Integer, null, (ushort)123 };
- yield return new object[] { "AJK", 0, 1, NumberStyles.HexNumber, new NumberFormatInfo(), (ushort)0XA };
- yield return new object[] { "$1,000", 0, 2, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (ushort)1 };
- yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (ushort)10 };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, ushort expected)
- {
- ushort result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(ushort.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, ushort.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(ushort.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- ushort result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(ushort.TryParse(value.AsSpan(), out result));
- Assert.Equal(0u, result);
- }
-
- Assert.Throws(exceptionType, () => ushort.Parse(value.AsSpan(), style, provider));
-
- Assert.False(ushort.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0u, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(ushort i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
namespace System.Tests
{
- public partial class UInt32Tests
+ public class UInt32Tests
{
[Fact]
public static void Ctor_Empty()
AssertExtensions.Throws<ArgumentException>(paramName, () => uint.Parse("1", style));
AssertExtensions.Throws<ArgumentException>(paramName, () => uint.Parse("1", style, null));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (uint)12 };
+ yield return new object[] { "123", 1, 2, NumberStyles.Integer, null, (uint)23 };
+ yield return new object[] { "4294967295", 0, 1, NumberStyles.Integer, null, 4 };
+ yield return new object[] { "4294967295", 9, 1, NumberStyles.Integer, null, 5 };
+ yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (uint)0x1 };
+ yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (uint)0x2 };
+ yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (uint)10 };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, uint expected)
+ {
+ uint result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(uint.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, uint.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(uint.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ uint result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(uint.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0u, result);
+ }
+
+ Assert.Throws(exceptionType, () => uint.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(uint.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0u, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(uint i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class UInt32Tests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (uint)12 };
- yield return new object[] { "123", 1, 2, NumberStyles.Integer, null, (uint)23 };
- yield return new object[] { "4294967295", 0, 1, NumberStyles.Integer, null, 4 };
- yield return new object[] { "4294967295", 9, 1, NumberStyles.Integer, null, 5 };
- yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (uint)0x1 };
- yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (uint)0x2 };
- yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (uint)10 };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, uint expected)
- {
- uint result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(uint.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, uint.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(uint.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- uint result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(uint.TryParse(value.AsSpan(), out result));
- Assert.Equal(0u, result);
- }
-
- Assert.Throws(exceptionType, () => uint.Parse(value.AsSpan(), style, provider));
-
- Assert.False(uint.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0u, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(uint i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
namespace System.Tests
{
- public partial class UInt64Tests
+ public class UInt64Tests
{
[Fact]
public static void Ctor_Empty()
AssertExtensions.Throws<ArgumentException>(paramName, () => ulong.Parse("1", style));
AssertExtensions.Throws<ArgumentException>(paramName, () => ulong.Parse("1", style, null));
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "+123", 1, 3, NumberStyles.Integer, null, (ulong)123 };
+ yield return new object[] { "+123", 0, 3, NumberStyles.Integer, null, (ulong)12 };
+ yield return new object[] { " 123 ", 1, 2, NumberStyles.Integer, null, (ulong)1 };
+ yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (ulong)0x1 };
+ yield return new object[] { "ABC", 1, 1, NumberStyles.HexNumber, null, (ulong)0xb };
+ yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (ulong)10 };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, ulong expected)
+ {
+ ulong result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(ulong.TryParse(value.AsSpan(offset, count), out result));
+ Assert.Equal(expected, result);
+ }
+
+ Assert.Equal(expected, ulong.Parse(value.AsSpan(offset, count), style, provider));
+
+ Assert.True(ulong.TryParse(value.AsSpan(offset, count), style, provider, out result));
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (value != null)
+ {
+ ulong result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(ulong.TryParse(value.AsSpan(), out result));
+ Assert.Equal(0u, result);
+ }
+
+ Assert.Throws(exceptionType, () => ulong.Parse(value.AsSpan(), style, provider));
+
+ Assert.False(ulong.TryParse(value.AsSpan(), style, provider, out result));
+ Assert.Equal(0u, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat(ulong i, string format, IFormatProvider provider, string expected)
+ {
+ char[] actual;
+ int charsWritten;
+
+ // Just right
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual));
+
+ // Longer than needed
+ actual = new char[expected.Length + 1];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected, new string(actual, 0, charsWritten));
+
+ // Too short
+ if (expected.Length > 0)
+ {
+ actual = new char[expected.Length - 1];
+ Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
+ Assert.Equal(0, charsWritten);
+ }
+
+ if (format != null)
+ {
+ // Upper format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToUpperInvariant(), new string(actual));
+
+ // Lower format
+ actual = new char[expected.Length];
+ Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
+ Assert.Equal(expected.Length, charsWritten);
+ Assert.Equal(expected.ToLowerInvariant(), new string(actual));
+ }
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class UInt64Tests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
- }
-
- yield return new object[] { "+123", 1, 3, NumberStyles.Integer, null, (ulong)123 };
- yield return new object[] { "+123", 0, 3, NumberStyles.Integer, null, (ulong)12 };
- yield return new object[] { " 123 ", 1, 2, NumberStyles.Integer, null, (ulong)1 };
- yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (ulong)0x1 };
- yield return new object[] { "ABC", 1, 1, NumberStyles.HexNumber, null, (ulong)0xb };
- yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (ulong)10 };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, ulong expected)
- {
- ulong result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.True(ulong.TryParse(value.AsSpan(offset, count), out result));
- Assert.Equal(expected, result);
- }
-
- Assert.Equal(expected, ulong.Parse(value.AsSpan(offset, count), style, provider));
-
- Assert.True(ulong.TryParse(value.AsSpan(offset, count), style, provider, out result));
- Assert.Equal(expected, result);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
- {
- if (value != null)
- {
- ulong result;
-
- // Default style and provider
- if (style == NumberStyles.Integer && provider == null)
- {
- Assert.False(ulong.TryParse(value.AsSpan(), out result));
- Assert.Equal(0u, result);
- }
-
- Assert.Throws(exceptionType, () => ulong.Parse(value.AsSpan(), style, provider));
-
- Assert.False(ulong.TryParse(value.AsSpan(), style, provider, out result));
- Assert.Equal(0u, result);
- }
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat(ulong i, string format, IFormatProvider provider, string expected)
- {
- char[] actual;
- int charsWritten;
-
- // Just right
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual));
-
- // Longer than needed
- actual = new char[expected.Length + 1];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected, new string(actual, 0, charsWritten));
-
- // Too short
- if (expected.Length > 0)
- {
- actual = new char[expected.Length - 1];
- Assert.False(i.TryFormat(actual.AsSpan(), out charsWritten, format, provider));
- Assert.Equal(0, charsWritten);
- }
-
- if (format != null)
- {
- // Upper format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToUpperInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToUpperInvariant(), new string(actual));
-
- // Lower format
- actual = new char[expected.Length];
- Assert.True(i.TryFormat(actual.AsSpan(), out charsWritten, format.ToLowerInvariant(), provider));
- Assert.Equal(expected.Length, charsWritten);
- Assert.Equal(expected.ToLowerInvariant(), new string(actual));
- }
- }
- }
-}
namespace System.Tests
{
- public static partial class UIntPtrTests
+ public static class UIntPtrTests
{
private static unsafe bool Is64Bit => sizeof(void*) == 8;
Assert.Equal(expected, ptr1 == ptr2);
Assert.Equal(!expected, ptr1 != ptr2);
Assert.Equal(expected, ptr1.GetHashCode().Equals(ptr2.GetHashCode()));
+
+ IEquatable<UIntPtr> iEquatable = ptr1;
+ Assert.Equal(expected, iEquatable.Equals((UIntPtr)obj));
}
Assert.Equal(expected, ptr1.Equals(obj));
Assert.Equal(ptr1.GetHashCode(), ptr1.GetHashCode());
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using Xunit;
-
-namespace System.Tests
-{
- public static partial class UIntPtrTests
- {
- [Theory]
- [MemberData(nameof(Equals_TestData))]
- public static void Equals_NetCoreApp11(UIntPtr ptr, object obj, bool expected)
- {
- if (!(obj is UIntPtr))
- {
- return;
- }
-
- IEquatable<UIntPtr> iEquatable = ptr;
- Assert.Equal(expected, iEquatable.Equals((UIntPtr)obj));
- }
- }
-}
namespace System.Tests
{
- public partial class VersionTests
+ public class VersionTests
{
[Fact]
public void Ctor_Default()
Assert.Equal(version.Build, clone.Build);
Assert.Equal(version.Revision, clone.Revision);
}
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1] };
+ }
+
+ yield return new object[] { "1.2.3", 0, 3, new Version(1, 2) };
+ yield return new object[] { "1.2.3", 2, 3, new Version(2, 3) };
+ yield return new object[] { "2 .3. 4. \t\r\n15 ", 0, 11, new Version(2, 3, 4) };
+ yield return new object[] { "+1.+2.+3.+4", 3, 5, new Version(2, 3) };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
+ public static void Parse_Span_ValidInput_ReturnsExpected(string input, int offset, int count, Version expected)
+ {
+ if (input == null)
+ {
+ return;
+ }
+
+ Assert.Equal(expected, Version.Parse(input.AsSpan(offset, count)));
+
+ Assert.True(Version.TryParse(input.AsSpan(offset, count), out Version version));
+ Assert.Equal(expected, version);
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Span_InvalidInput_ThrowsException(string input, Type exceptionType)
+ {
+ if (input == null)
+ {
+ return;
+ }
+
+ Assert.Throws(exceptionType, () => Version.Parse(input.AsSpan()));
+
+ Assert.False(Version.TryParse(input.AsSpan(), out Version version));
+ Assert.Null(version);
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void TryFormat_Invoke_WritesExpected(Version version, string[] expected)
+ {
+ char[] dest;
+ int charsWritten;
+
+ for (int i = 0; i < expected.Length; i++)
+ {
+ if (i > 0)
+ {
+ // Too small
+ dest = new char[expected[i].Length - 1];
+ Assert.False(version.TryFormat(dest, i, out charsWritten));
+ Assert.Equal(0, charsWritten);
+ }
+
+ // Just right
+ dest = new char[expected[i].Length];
+ Assert.True(version.TryFormat(dest, i, out charsWritten));
+ Assert.Equal(expected[i].Length, charsWritten);
+ Assert.Equal(expected[i], new string(dest, 0, charsWritten));
+
+ // More than needed
+ dest = new char[expected[i].Length + 10];
+ Assert.True(version.TryFormat(dest, i, out charsWritten));
+ Assert.Equal(expected[i].Length, charsWritten);
+ Assert.Equal(expected[i], new string(dest, 0, charsWritten));
+ }
+
+ int maxFieldCount = expected.Length - 1;
+ dest = new char[expected[maxFieldCount].Length];
+ Assert.True(version.TryFormat(dest, out charsWritten));
+ Assert.Equal(expected[maxFieldCount].Length, charsWritten);
+ Assert.Equal(expected[maxFieldCount], new string(dest, 0, charsWritten));
+
+ dest = new char[0];
+ AssertExtensions.Throws<ArgumentException>("fieldCount", () => version.TryFormat(dest, -1, out charsWritten)); // Index < 0
+ AssertExtensions.Throws<ArgumentException>("fieldCount", () => version.TryFormat(dest, maxFieldCount + 1, out charsWritten)); // Index > version.fieldCount
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using Xunit;
-
-namespace System.Tests
-{
- public partial class VersionTests
- {
- public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
- {
- foreach (object[] inputs in Parse_Valid_TestData())
- {
- yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1] };
- }
-
- yield return new object[] { "1.2.3", 0, 3, new Version(1, 2) };
- yield return new object[] { "1.2.3", 2, 3, new Version(2, 3) };
- yield return new object[] { "2 .3. 4. \t\r\n15 ", 0, 11, new Version(2, 3, 4) };
- yield return new object[] { "+1.+2.+3.+4", 3, 5, new Version(2, 3) };
- }
-
- [Theory]
- [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))]
- public static void Parse_Span_ValidInput_ReturnsExpected(string input, int offset, int count, Version expected)
- {
- if (input == null)
- {
- return;
- }
-
- Assert.Equal(expected, Version.Parse(input.AsSpan(offset, count)));
-
- Assert.True(Version.TryParse(input.AsSpan(offset, count), out Version version));
- Assert.Equal(expected, version);
- }
-
- [Theory]
- [MemberData(nameof(Parse_Invalid_TestData))]
- public static void Parse_Span_InvalidInput_ThrowsException(string input, Type exceptionType)
- {
- if (input == null)
- {
- return;
- }
-
- Assert.Throws(exceptionType, () => Version.Parse(input.AsSpan()));
-
- Assert.False(Version.TryParse(input.AsSpan(), out Version version));
- Assert.Null(version);
- }
-
- [Theory]
- [MemberData(nameof(ToString_TestData))]
- public static void TryFormat_Invoke_WritesExpected(Version version, string[] expected)
- {
- char[] dest;
- int charsWritten;
-
- for (int i = 0; i < expected.Length; i++)
- {
- if (i > 0)
- {
- // Too small
- dest = new char[expected[i].Length - 1];
- Assert.False(version.TryFormat(dest, i, out charsWritten));
- Assert.Equal(0, charsWritten);
- }
-
- // Just right
- dest = new char[expected[i].Length];
- Assert.True(version.TryFormat(dest, i, out charsWritten));
- Assert.Equal(expected[i].Length, charsWritten);
- Assert.Equal(expected[i], new string(dest, 0, charsWritten));
-
- // More than needed
- dest = new char[expected[i].Length + 10];
- Assert.True(version.TryFormat(dest, i, out charsWritten));
- Assert.Equal(expected[i].Length, charsWritten);
- Assert.Equal(expected[i], new string(dest, 0, charsWritten));
- }
-
- int maxFieldCount = expected.Length - 1;
- dest = new char[expected[maxFieldCount].Length];
- Assert.True(version.TryFormat(dest, out charsWritten));
- Assert.Equal(expected[maxFieldCount].Length, charsWritten);
- Assert.Equal(expected[maxFieldCount], new string(dest, 0, charsWritten));
-
- dest = new char[0];
- AssertExtensions.Throws<ArgumentException>("fieldCount", () => version.TryFormat(dest, -1, out charsWritten)); // Index < 0
- AssertExtensions.Throws<ArgumentException>("fieldCount", () => version.TryFormat(dest, maxFieldCount + 1, out charsWritten)); // Index > version.fieldCount
- }
- }
-}