From: Roman Marusyk Date: Mon, 28 Oct 2019 03:22:40 +0000 (+0100) Subject: Consolidate .netcoreapp.cs test files in System.Runtime (dotnet/corefx#42100) X-Git-Tag: submit/tizen/20210909.063632~11031^2~171 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=181005f1f6e936575730bc049c9f15934cab4586;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Consolidate .netcoreapp.cs test files in System.Runtime (dotnet/corefx#42100) * Consolidate .netcoreapp.cs files because System.Runtime project is no longer cross-compiled Commit migrated from https://github.com/dotnet/corefx/commit/d6dac9e6a7875862b91139334c8ec620f599cd4d --- diff --git a/src/libraries/System.Runtime/tests/Helpers.netcoreapp.cs b/src/libraries/System.Runtime/tests/Helpers.cs similarity index 97% rename from src/libraries/System.Runtime/tests/Helpers.netcoreapp.cs rename to src/libraries/System.Runtime/tests/Helpers.cs index fcfe264..a092d70 100644 --- a/src/libraries/System.Runtime/tests/Helpers.netcoreapp.cs +++ b/src/libraries/System.Runtime/tests/Helpers.cs @@ -9,7 +9,7 @@ using System.Reflection.Emit; namespace System.Tests { - public static partial class Helpers + public static class Helpers { private static Type s_refEmitType; diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 9cec3de..c306add0 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -46,11 +46,13 @@ Common\System\Collections\IEnumerable.NonGeneric.Tests.cs + + @@ -91,7 +93,9 @@ + + @@ -122,12 +126,14 @@ + + @@ -135,6 +141,7 @@ + @@ -189,10 +196,13 @@ + + + @@ -232,74 +242,22 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + - - - - - - - - - - - - - - - - + + + + + + + + + - + diff --git a/src/libraries/System.Runtime/tests/System/ActivatorTests.cs b/src/libraries/System.Runtime/tests/System/ActivatorTests.cs index a32ac63..27c458e 100644 --- a/src/libraries/System.Runtime/tests/System/ActivatorTests.cs +++ b/src/libraries/System.Runtime/tests/System/ActivatorTests.cs @@ -4,8 +4,13 @@ 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 @@ -563,5 +568,266 @@ 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(() => Activator.CreateInstance(type)); + Assert.Throws(() => 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(() => Activator.CreateInstance(type)); + Assert.Throws(() => 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 TestingCreateInstanceFromObjectHandleData => new TheoryData() + { + // 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 TestingCreateInstanceObjectHandleData => new TheoryData() + { + // 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 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 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 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(() => 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("type", () => Activator.CreateInstance(typeBuilder)); + Assert.Throws(() => Activator.CreateInstance(typeBuilder, new object[0])); + } } } diff --git a/src/libraries/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs deleted file mode 100644 index fb2f85f..0000000 --- a/src/libraries/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs +++ /dev/null @@ -1,280 +0,0 @@ -// 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(() => Activator.CreateInstance(type)); - Assert.Throws(() => 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(() => Activator.CreateInstance(type)); - Assert.Throws(() => 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 TestingCreateInstanceFromObjectHandleData => new TheoryData() - { - // 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 TestingCreateInstanceObjectHandleData => new TheoryData() - { - // 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 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 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 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(() => 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("type", () => Activator.CreateInstance(typeBuilder)); - Assert.Throws(() => Activator.CreateInstance(typeBuilder, new object[0])); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/ArgIteratorTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/ArgIteratorTests.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/ArgIteratorTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/ArgIteratorTests.cs diff --git a/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs b/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs index 343e93d..986c7ca 100644 --- a/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs @@ -88,6 +88,116 @@ namespace System.Tests AssertExtensions.Throws(null, () => new ArraySegment(new T[10], 10, 1)); // Offset + count > array.Length AssertExtensions.Throws(null, () => new ArraySegment(new T[10], 9, 2)); // Offset + count > array.Length } + + [Fact] + public void CopyTo_Default_ThrowsInvalidOperationException() + { + // Source is default + Assert.Throws(() => default(ArraySegment).CopyTo(new T[0])); + Assert.Throws(() => default(ArraySegment).CopyTo(new T[0], 0)); + Assert.Throws(() => ((ICollection)default(ArraySegment)).CopyTo(new T[0], 0)); + Assert.Throws(() => default(ArraySegment).CopyTo(new ArraySegment(new T[0]))); + + // Destination is default + Assert.Throws(() => new ArraySegment(new T[0]).CopyTo(default(ArraySegment))); + } + + [Fact] + public void Empty() + { + ArraySegment empty = ArraySegment.Empty; + + // Assert.NotEqual uses its own Comparer, when it is comparing IEnumerables it calls GetEnumerator() + // ArraySegment.GetEnumerator() throws InvalidOperationException when the array is null and default() returns null + Assert.True(default(ArraySegment) != empty); + + // Check that two Empty invocations return equal ArraySegments. + Assert.Equal(empty, ArraySegment.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.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(new T[1], 0, 1); + var ienumerableoft = (IEnumerable)arraySegment; + var ienumerable = (IEnumerable)arraySegment; + + ArraySegment.Enumerator enumerator = arraySegment.GetEnumerator(); + Assert.IsType.Enumerator>(enumerator); + Assert.IsAssignableFrom>(enumerator); + Assert.IsAssignableFrom(enumerator); + + IEnumerator 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(() => default(ArraySegment).GetEnumerator()); + } + + [Fact] + public void Slice_Default_ThrowsInvalidOperationException() + { + Assert.Throws(() => default(ArraySegment).Slice(0)); + Assert.Throws(() => default(ArraySegment).Slice(0, 0)); + } + + [Fact] + public void ToArray_Default_ThrowsInvalidOperationException() + { + Assert.Throws(() => default(ArraySegment).ToArray()); + } + + [Fact] + public void ToArray_Empty_ReturnsSameArray() + { + T[] cachedArray = ArraySegment.Empty.ToArray(); + Assert.Same(cachedArray, ArraySegment.Empty.ToArray()); + Assert.Same(cachedArray, new ArraySegment(new T[0]).ToArray()); + Assert.Same(cachedArray, new ArraySegment(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(new T[1], 0, 0); + Assert.NotSame(emptyArraySegment.Array, emptyArraySegment.ToArray()); + } + + [Fact] + public void Cast_FromNullArray_ReturnsDefault() + { + ArraySegment fromNull = null; + Assert.Null(fromNull.Array); + Assert.Equal(0, fromNull.Offset); + Assert.Equal(0, fromNull.Count); + + Assert.True(default(ArraySegment) == null); + Assert.True(new ArraySegment(Array.Empty()) != null); + } + + [Fact] + public void Cast_FromValidArray_ReturnsSegmentForWholeArray() + { + var array = new T[42]; + ArraySegment fromArray = array; + Assert.Same(array, fromArray.Array); + Assert.Equal(0, fromArray.Offset); + Assert.Equal(42, fromArray.Count); + } } public class ArraySegment_Tests_string : ArraySegment_Tests @@ -272,5 +382,352 @@ namespace System.Tests (enumerator as IEnumerator).Reset(); } } + + [Theory] + [MemberData(nameof(Conversion_FromArray_TestData))] + public static void Conversion_FromArray(int[] array) + { + ArraySegment implicitlyConverted = array; + ArraySegment explicitlyConverted = (ArraySegment)array; + + var expected = new ArraySegment(array); + Assert.Equal(expected, implicitlyConverted); + Assert.Equal(expected, explicitlyConverted); + } + + public static IEnumerable 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 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.CopyTo(T[], int) + CopyAndInvoke(destinationModel, destination => + { + ((ICollection)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) + 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(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[] array, Action action) => action(array.ToArray()); + + [Theory] + [MemberData(nameof(ArraySegment_TestData))] + public static void CopyTo_Invalid(ArraySegment arraySegment) + { + int count = arraySegment.Count; + + // ArraySegment.CopyTo calls Array.Copy internally, so the exception parameter names come from there. + + // Destination is null + AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(null)); + AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(null, 0)); + + // Destination index not within range + AssertExtensions.Throws("destinationIndex", () => arraySegment.CopyTo(new int[0], -1)); + + // Destination array too small arraySegment.Count + destinationIndex > destinationArray.Length + AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(new int[arraySegment.Count * 2], arraySegment.Count + 1)); + + if (arraySegment.Any()) + { + // Destination not large enough + AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(new int[count - 1])); + AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(new int[count - 1], 0)); + AssertExtensions.Throws("destination", null, () => arraySegment.CopyTo(new ArraySegment(new int[count - 1]))); + + // Don't write beyond the limits of the destination in cases where source.Count > destination.Count + AssertExtensions.Throws("destination", null, () => arraySegment.CopyTo(new ArraySegment(new int[count], 1, 0))); // destination.Array can't fit source at destination.Offset + AssertExtensions.Throws("destination", null, () => arraySegment.CopyTo(new ArraySegment(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 arraySegment) + { + int[] array = arraySegment.Array; + int index = arraySegment.Offset; + int count = arraySegment.Count; + + ArraySegment.Enumerator enumerator = arraySegment.GetEnumerator(); + + var actual = new List(); + + while (enumerator.MoveNext()) + { + actual.Add(enumerator.Current); + } + + // After MoveNext returns false once, it should return false the second time. + Assert.False(enumerator.MoveNext()); + + IEnumerable expected = array.Skip(index).Take(count); + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(ArraySegment_TestData))] + public static void GetEnumerator_Dispose(ArraySegment arraySegment) + { + int[] array = arraySegment.Array; + int index = arraySegment.Offset; + + ArraySegment.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 arraySegment) + { + int[] array = arraySegment.Array; + int index = arraySegment.Offset; + int count = arraySegment.Count; + + var enumerator = (IEnumerator)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 arraySegment) + { + ArraySegment.Enumerator enumerator = arraySegment.GetEnumerator(); + + // Before beginning + Assert.Throws(() => enumerator.Current); + Assert.Throws(() => ((IEnumerator)enumerator).Current); + Assert.Throws(() => ((IEnumerator)enumerator).Current); + + while (enumerator.MoveNext()) ; + + // After end + Assert.Throws(() => enumerator.Current); + Assert.Throws(() => ((IEnumerator)enumerator).Current); + Assert.Throws(() => ((IEnumerator)enumerator).Current); + } + + [Theory] + [MemberData(nameof(ArraySegment_TestData))] + public static void GetSetItem_InRange(ArraySegment 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)arraySegment)[i]); + Assert.Equal(expected[i], ((IReadOnlyList)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 arraySegment) + { + int[] array = arraySegment.Array; + + // Before array start + Assert.Throws(() => arraySegment[-arraySegment.Offset - 1]); + Assert.Throws(() => arraySegment[-arraySegment.Offset - 1] = default(int)); + + // After array start (if Offset > 0), before start + Assert.Throws(() => arraySegment[-1]); + Assert.Throws(() => arraySegment[-1] = default(int)); + + // Before array end (if Offset + Count < Array.Length), after end + Assert.Throws(() => arraySegment[arraySegment.Count]); + Assert.Throws(() => arraySegment[arraySegment.Count] = default(int)); + + // After array end + Assert.Throws(() => arraySegment[-arraySegment.Offset + array.Length]); + Assert.Throws(() => arraySegment[-arraySegment.Offset + array.Length] = default(int)); + } + + [Theory] + [MemberData(nameof(Slice_TestData))] + public static void Slice(ArraySegment arraySegment, int index, int count) + { + var expected = new ArraySegment(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 Slice_TestData() + { + IEnumerable> arraySegments = ArraySegment_TestData().Select(array => array.Single()).Cast>(); + + foreach (ArraySegment 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 arraySegment, int index, int count) + { + if (index + count == arraySegment.Count) + { + AssertExtensions.Throws("index", () => arraySegment.Slice(index)); + } + + AssertExtensions.Throws("index", () => arraySegment.Slice(index, count)); + } + + public static IEnumerable Slice_Invalid_TestData() + { + var arraySegment = new ArraySegment(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 arraySegment) + { + // ToList is called here so we copy the data and raise an assert if ToArray modifies the underlying array. + List expected = arraySegment.Array.Skip(arraySegment.Offset).Take(arraySegment.Count).ToList(); + Assert.Equal(expected, arraySegment.ToArray()); + } + + public static IEnumerable 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(aseg.array, aseg.index, aseg.count) }); + } } } diff --git a/src/libraries/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs deleted file mode 100644 index 3247fd1..0000000 --- a/src/libraries/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs +++ /dev/null @@ -1,474 +0,0 @@ -// 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 - { - [Fact] - public void CopyTo_Default_ThrowsInvalidOperationException() - { - // Source is default - Assert.Throws(() => default(ArraySegment).CopyTo(new T[0])); - Assert.Throws(() => default(ArraySegment).CopyTo(new T[0], 0)); - Assert.Throws(() => ((ICollection)default(ArraySegment)).CopyTo(new T[0], 0)); - Assert.Throws(() => default(ArraySegment).CopyTo(new ArraySegment(new T[0]))); - - // Destination is default - Assert.Throws(() => new ArraySegment(new T[0]).CopyTo(default(ArraySegment))); - } - - [Fact] - public void Empty() - { - ArraySegment empty = ArraySegment.Empty; - - // Assert.NotEqual uses its own Comparer, when it is comparing IEnumerables it calls GetEnumerator() - // ArraySegment.GetEnumerator() throws InvalidOperationException when the array is null and default() returns null - Assert.True(default(ArraySegment) != empty); - - // Check that two Empty invocations return equal ArraySegments. - Assert.Equal(empty, ArraySegment.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.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(new T[1], 0, 1); - var ienumerableoft = (IEnumerable)arraySegment; - var ienumerable = (IEnumerable)arraySegment; - - ArraySegment.Enumerator enumerator = arraySegment.GetEnumerator(); - Assert.IsType.Enumerator>(enumerator); - Assert.IsAssignableFrom>(enumerator); - Assert.IsAssignableFrom(enumerator); - - IEnumerator 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(() => default(ArraySegment).GetEnumerator()); - } - - [Fact] - public void Slice_Default_ThrowsInvalidOperationException() - { - Assert.Throws(() => default(ArraySegment).Slice(0)); - Assert.Throws(() => default(ArraySegment).Slice(0, 0)); - } - - [Fact] - public void ToArray_Default_ThrowsInvalidOperationException() - { - Assert.Throws(() => default(ArraySegment).ToArray()); - } - - [Fact] - public void ToArray_Empty_ReturnsSameArray() - { - T[] cachedArray = ArraySegment.Empty.ToArray(); - Assert.Same(cachedArray, ArraySegment.Empty.ToArray()); - Assert.Same(cachedArray, new ArraySegment(new T[0]).ToArray()); - Assert.Same(cachedArray, new ArraySegment(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(new T[1], 0, 0); - Assert.NotSame(emptyArraySegment.Array, emptyArraySegment.ToArray()); - } - - [Fact] - public void Cast_FromNullArray_ReturnsDefault() - { - ArraySegment fromNull = null; - Assert.Null(fromNull.Array); - Assert.Equal(0, fromNull.Offset); - Assert.Equal(0, fromNull.Count); - - Assert.True(default(ArraySegment) == null); - Assert.True(new ArraySegment(Array.Empty()) != null); - } - - [Fact] - public void Cast_FromValidArray_ReturnsSegmentForWholeArray() - { - var array = new T[42]; - ArraySegment 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 implicitlyConverted = array; - ArraySegment explicitlyConverted = (ArraySegment)array; - - var expected = new ArraySegment(array); - Assert.Equal(expected, implicitlyConverted); - Assert.Equal(expected, explicitlyConverted); - } - - public static IEnumerable 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 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.CopyTo(T[], int) - CopyAndInvoke(destinationModel, destination => - { - ((ICollection)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) - 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(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[] array, Action action) => action(array.ToArray()); - - [Theory] - [MemberData(nameof(ArraySegment_TestData))] - public static void CopyTo_Invalid(ArraySegment arraySegment) - { - int count = arraySegment.Count; - - // ArraySegment.CopyTo calls Array.Copy internally, so the exception parameter names come from there. - - // Destination is null - AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(null)); - AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(null, 0)); - - // Destination index not within range - AssertExtensions.Throws("destinationIndex", () => arraySegment.CopyTo(new int[0], -1)); - - // Destination array too small arraySegment.Count + destinationIndex > destinationArray.Length - AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(new int[arraySegment.Count * 2], arraySegment.Count + 1)); - - if (arraySegment.Any()) - { - // Destination not large enough - AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(new int[count - 1])); - AssertExtensions.Throws("destinationArray", () => arraySegment.CopyTo(new int[count - 1], 0)); - AssertExtensions.Throws("destination", null, () => arraySegment.CopyTo(new ArraySegment(new int[count - 1]))); - - // Don't write beyond the limits of the destination in cases where source.Count > destination.Count - AssertExtensions.Throws("destination", null, () => arraySegment.CopyTo(new ArraySegment(new int[count], 1, 0))); // destination.Array can't fit source at destination.Offset - AssertExtensions.Throws("destination", null, () => arraySegment.CopyTo(new ArraySegment(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 arraySegment) - { - int[] array = arraySegment.Array; - int index = arraySegment.Offset; - int count = arraySegment.Count; - - ArraySegment.Enumerator enumerator = arraySegment.GetEnumerator(); - - var actual = new List(); - - while (enumerator.MoveNext()) - { - actual.Add(enumerator.Current); - } - - // After MoveNext returns false once, it should return false the second time. - Assert.False(enumerator.MoveNext()); - - IEnumerable expected = array.Skip(index).Take(count); - Assert.Equal(expected, actual); - } - - [Theory] - [MemberData(nameof(ArraySegment_TestData))] - public static void GetEnumerator_Dispose(ArraySegment arraySegment) - { - int[] array = arraySegment.Array; - int index = arraySegment.Offset; - - ArraySegment.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 arraySegment) - { - int[] array = arraySegment.Array; - int index = arraySegment.Offset; - int count = arraySegment.Count; - - var enumerator = (IEnumerator)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 arraySegment) - { - ArraySegment.Enumerator enumerator = arraySegment.GetEnumerator(); - - // Before beginning - Assert.Throws(() => enumerator.Current); - Assert.Throws(() => ((IEnumerator)enumerator).Current); - Assert.Throws(() => ((IEnumerator)enumerator).Current); - - while (enumerator.MoveNext()) ; - - // After end - Assert.Throws(() => enumerator.Current); - Assert.Throws(() => ((IEnumerator)enumerator).Current); - Assert.Throws(() => ((IEnumerator)enumerator).Current); - } - - [Theory] - [MemberData(nameof(ArraySegment_TestData))] - public static void GetSetItem_InRange(ArraySegment 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)arraySegment)[i]); - Assert.Equal(expected[i], ((IReadOnlyList)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 arraySegment) - { - int[] array = arraySegment.Array; - - // Before array start - Assert.Throws(() => arraySegment[-arraySegment.Offset - 1]); - Assert.Throws(() => arraySegment[-arraySegment.Offset - 1] = default(int)); - - // After array start (if Offset > 0), before start - Assert.Throws(() => arraySegment[-1]); - Assert.Throws(() => arraySegment[-1] = default(int)); - - // Before array end (if Offset + Count < Array.Length), after end - Assert.Throws(() => arraySegment[arraySegment.Count]); - Assert.Throws(() => arraySegment[arraySegment.Count] = default(int)); - - // After array end - Assert.Throws(() => arraySegment[-arraySegment.Offset + array.Length]); - Assert.Throws(() => arraySegment[-arraySegment.Offset + array.Length] = default(int)); - } - - [Theory] - [MemberData(nameof(Slice_TestData))] - public static void Slice(ArraySegment arraySegment, int index, int count) - { - var expected = new ArraySegment(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 Slice_TestData() - { - IEnumerable> arraySegments = ArraySegment_TestData().Select(array => array.Single()).Cast>(); - - foreach (ArraySegment 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 arraySegment, int index, int count) - { - if (index + count == arraySegment.Count) - { - AssertExtensions.Throws("index", () => arraySegment.Slice(index)); - } - - AssertExtensions.Throws("index", () => arraySegment.Slice(index, count)); - } - - public static IEnumerable Slice_Invalid_TestData() - { - var arraySegment = new ArraySegment(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 arraySegment) - { - // ToList is called here so we copy the data and raise an assert if ToArray modifies the underlying array. - List expected = arraySegment.Array.Skip(arraySegment.Offset).Take(arraySegment.Count).ToList(); - Assert.Equal(expected, arraySegment.ToArray()); - } - - public static IEnumerable 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(aseg.array, aseg.index, aseg.count) }); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/ArrayTests.cs b/src/libraries/System.Runtime/tests/System/ArrayTests.cs index 4375e6d..bf0ef63 100644 --- a/src/libraries/System.Runtime/tests/System/ArrayTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArrayTests.cs @@ -7,11 +7,12 @@ using System.Collections.Generic; 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() @@ -4064,6 +4065,188 @@ namespace System.Tests Array.Reverse((Array)new int*[1]); } + public static IEnumerable Fill_Generic_TestData() + { + var data = Enumerable.Empty(); + + var r = new Random(0x051778f7); + int[] lengths = { 0, 1, 2, 3, 5, 8, 13 }; + + foreach (int length in lengths) + { + IEnumerable 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(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 GenerateFillData(IEnumerable source, TSource seed, Func 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 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(IEnumerable 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("array", () => Array.Fill(null, 1)); + AssertExtensions.Throws("array", () => Array.Fill(null, 1, 0, 0)); + } + + [Theory] + [InlineData(-1)] + [InlineData(2)] + public void Fill_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) + { + AssertExtensions.Throws("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("count", () => Array.Fill(new string[arrayLength], "", startIndex, count)); + } + + public static IEnumerable 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("array", () => Array.Reverse((string[])null)); + AssertExtensions.Throws("array", () => Array.Reverse((string[])null, 0, 0)); + } + + [Fact] + public static void Reverse_Generic_NegativeIndex_ThrowsArgumentOutOfRangeException() + { + AssertExtensions.Throws("index", () => Array.Reverse(new string[0], -1, 0)); + } + + [Fact] + public static void Reverse_Generic_NegativeLength_ThrowsArgumentOutOfRangeException() + { + AssertExtensions.Throws("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(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("elementType", () => Array.CreateInstance(elementType, 1)); + AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, 1, 1)); + AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, 1, 1, 1)); + AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, new int[1])); + AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, new long[1])); + AssertExtensions.Throws("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); diff --git a/src/libraries/System.Runtime/tests/System/ArrayTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/ArrayTests.netcoreapp.cs deleted file mode 100644 index 457556f..0000000 --- a/src/libraries/System.Runtime/tests/System/ArrayTests.netcoreapp.cs +++ /dev/null @@ -1,196 +0,0 @@ -// 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 Fill_Generic_TestData() - { - var data = Enumerable.Empty(); - - var r = new Random(0x051778f7); - int[] lengths = { 0, 1, 2, 3, 5, 8, 13 }; - - foreach (int length in lengths) - { - IEnumerable 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(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 GenerateFillData(IEnumerable source, TSource seed, Func 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 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(IEnumerable 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("array", () => Array.Fill(null, 1)); - AssertExtensions.Throws("array", () => Array.Fill(null, 1, 0, 0)); - } - - [Theory] - [InlineData(-1)] - [InlineData(2)] - public void Fill_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) - { - AssertExtensions.Throws("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("count", () => Array.Fill(new string[arrayLength], "", startIndex, count)); - } - - public static IEnumerable 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("array", () => Array.Reverse((string[])null)); - AssertExtensions.Throws("array", () => Array.Reverse((string[])null, 0, 0)); - } - - [Fact] - public static void Reverse_Generic_NegativeIndex_ThrowsArgumentOutOfRangeException() - { - AssertExtensions.Throws("index", () => Array.Reverse(new string[0], -1, 0)); - } - - [Fact] - public static void Reverse_Generic_NegativeLength_ThrowsArgumentOutOfRangeException() - { - AssertExtensions.Throws("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(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("elementType", () => Array.CreateInstance(elementType, 1)); - AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, 1, 1)); - AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, 1, 1, 1)); - AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, new int[1])); - AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, new long[1])); - AssertExtensions.Throws("elementType", () => Array.CreateInstance(elementType, new int[1], new int[1])); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/BooleanTests.cs b/src/libraries/System.Runtime/tests/System/BooleanTests.cs index f56c28a..bb6073f 100644 --- a/src/libraries/System.Runtime/tests/System/BooleanTests.cs +++ b/src/libraries/System.Runtime/tests/System/BooleanTests.cs @@ -146,5 +146,68 @@ namespace System.Tests { Assert.Equal(TypeCode.Boolean, true.GetTypeCode()); } + + public static IEnumerable 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); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/BooleanTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/BooleanTests.netcoreapp.cs deleted file mode 100644 index 3d23b79..0000000 --- a/src/libraries/System.Runtime/tests/System/BooleanTests.netcoreapp.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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 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); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/ByteTests.cs b/src/libraries/System.Runtime/tests/System/ByteTests.cs index 570abba..5522c8e 100644 --- a/src/libraries/System.Runtime/tests/System/ByteTests.cs +++ b/src/libraries/System.Runtime/tests/System/ByteTests.cs @@ -8,7 +8,7 @@ using Xunit; namespace System.Tests { - public partial class ByteTests + public class ByteTests { [Fact] public static void Ctor_Empty() @@ -288,5 +288,106 @@ namespace System.Tests AssertExtensions.Throws(paramName, () => byte.Parse("1", style)); AssertExtensions.Throws(paramName, () => byte.Parse("1", style, null)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/ByteTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/ByteTests.netcoreapp.cs deleted file mode 100644 index 01103fc..0000000 --- a/src/libraries/System.Runtime/tests/System/ByteTests.netcoreapp.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/CharTests.cs b/src/libraries/System.Runtime/tests/System/CharTests.cs index b7a6a47..055c046 100644 --- a/src/libraries/System.Runtime/tests/System/CharTests.cs +++ b/src/libraries/System.Runtime/tests/System/CharTests.cs @@ -5,11 +5,13 @@ 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)] @@ -1106,5 +1108,159 @@ namespace System.Tests 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.")); + } + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/CharTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/CharTests.netcoreapp.cs deleted file mode 100644 index 5af4344..0000000 --- a/src/libraries/System.Runtime/tests/System/CharTests.netcoreapp.cs +++ /dev/null @@ -1,168 +0,0 @@ -// 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.")); - } - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyValuePairTests.cs b/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyValuePairTests.cs index c4bcf03..7666aeb 100644 --- a/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyValuePairTests.cs +++ b/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyValuePairTests.cs @@ -6,7 +6,7 @@ using Xunit; namespace System.Collections.Generic.Tests { - public partial class KeyValuePairTests + public class KeyValuePairTests { [Fact] public void Ctor_KeyValue_ReturnsExpected() @@ -43,5 +43,13 @@ namespace System.Collections.Generic.Tests var keyValuePair = new KeyValuePair(null, null); Assert.Equal("[, ]", keyValuePair.ToString()); } + + [Fact] + public void Create_ReturnsExpected() + { + KeyValuePair keyValuePair = KeyValuePair.Create(1, "2"); + Assert.Equal(1, keyValuePair.Key); + Assert.Equal("2", keyValuePair.Value); + } } } diff --git a/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyValuePairTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyValuePairTests.netcoreapp.cs deleted file mode 100644 index 3b84d01..0000000 --- a/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyValuePairTests.netcoreapp.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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 keyValuePair = KeyValuePair.Create(1, "2"); - Assert.Equal(1, keyValuePair.Key); - Assert.Equal("2", keyValuePair.Value); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/ComponentModel/DefaultValueAttributeTests.cs b/src/libraries/System.Runtime/tests/System/ComponentModel/DefaultValueAttributeTests.cs index 19b3104..038ee85 100644 --- a/src/libraries/System.Runtime/tests/System/ComponentModel/DefaultValueAttributeTests.cs +++ b/src/libraries/System.Runtime/tests/System/ComponentModel/DefaultValueAttributeTests.cs @@ -11,7 +11,7 @@ using Xunit; namespace System.ComponentModel.Tests { - public partial class DefaultValueAttributeTests + public class DefaultValueAttributeTests { [Fact] public static void Ctor() @@ -23,9 +23,16 @@ namespace System.ComponentModel.Tests 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); diff --git a/src/libraries/System.Runtime/tests/System/ComponentModel/DefaultValueAttributeTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/ComponentModel/DefaultValueAttributeTests.netcoreapp.cs deleted file mode 100644 index 178de91..0000000 --- a/src/libraries/System.Runtime/tests/System/ComponentModel/DefaultValueAttributeTests.netcoreapp.cs +++ /dev/null @@ -1,21 +0,0 @@ -// 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); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs index 7c9a42c..fef1844 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs @@ -10,7 +10,7 @@ using Xunit; namespace System.Tests { - public static partial class DateTimeOffsetTests + public static class DateTimeOffsetTests { [Fact] public static void MaxValue() @@ -1275,5 +1275,98 @@ namespace System.Tests { 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 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 actual = new char[expectedString.Length]; + Assert.True(expected.TryFormat(actual, out int charsWritten)); + Assert.Equal(expectedString.Length, charsWritten); + Assert.Equal(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(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); + } } } diff --git a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs deleted file mode 100644 index c927975..0000000 --- a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs +++ /dev/null @@ -1,105 +0,0 @@ -// 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 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 actual = new char[expectedString.Length]; - Assert.True(expected.TryFormat(actual, out int charsWritten)); - Assert.Equal(expectedString.Length, charsWritten); - Assert.Equal(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(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); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs index a390144..ff8964f 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs @@ -12,7 +12,7 @@ using Xunit; namespace System.Tests { - public partial class DateTimeTests + public class DateTimeTests { [Fact] public static void MaxValue() @@ -2273,5 +2273,98 @@ namespace System.Tests 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 dest = new char[expected.Length]; + Assert.True(dt.TryFormat(dest, out int charsWritten, format)); + Assert.Equal(expected.Length, charsWritten); + Assert.Equal(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(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(() => DateTime.ParseExact(input.AsSpan(), format, culture, style)); + Assert.Throws(() => 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); + } } } diff --git a/src/libraries/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs deleted file mode 100644 index 13eee84..0000000 --- a/src/libraries/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs +++ /dev/null @@ -1,105 +0,0 @@ -// 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 dest = new char[expected.Length]; - Assert.True(dt.TryFormat(dest, out int charsWritten, format)); - Assert.Equal(expected.Length, charsWritten); - Assert.Equal(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(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(() => DateTime.ParseExact(input.AsSpan(), format, culture, style)); - Assert.Throws(() => 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); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/DecimalTests.cs b/src/libraries/System.Runtime/tests/System/DecimalTests.cs index 8d2b8ed..f132752 100644 --- a/src/libraries/System.Runtime/tests/System/DecimalTests.cs +++ b/src/libraries/System.Runtime/tests/System/DecimalTests.cs @@ -12,7 +12,7 @@ using Xunit; namespace System.Tests { - public partial class DecimalTests + public class DecimalTests { [Fact] public void MaxValue_Get_ReturnsExpected() @@ -2179,5 +2179,127 @@ namespace System.Tests return new BigDecimal(res, (byte)scale); } } + + [Theory] + [InlineData(MidpointRounding.ToEven - 1)] + [InlineData(MidpointRounding.ToPositiveInfinity + 1)] + public void Round_InvalidMidpointRounding_ThrowsArgumentException(MidpointRounding mode) + { + AssertExtensions.Throws("mode", () => decimal.Round(1, 2, mode)); + } + + public static IEnumerable 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}"); + } + } + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/DecimalTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/DecimalTests.netcoreapp.cs deleted file mode 100644 index fcd5b81..0000000 --- a/src/libraries/System.Runtime/tests/System/DecimalTests.netcoreapp.cs +++ /dev/null @@ -1,136 +0,0 @@ -// 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("mode", () => decimal.Round(1, 2, mode)); - } - - public static IEnumerable 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}"); - } - } - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/DoubleTests.cs b/src/libraries/System.Runtime/tests/System/DoubleTests.cs index c1b4fe3..de096f5 100644 --- a/src/libraries/System.Runtime/tests/System/DoubleTests.cs +++ b/src/libraries/System.Runtime/tests/System/DoubleTests.cs @@ -11,7 +11,7 @@ using Xunit; namespace System.Tests { - public partial class DoubleTests + public class DoubleTests { // NOTE: Consider duplicating any tests added here in SingleTests.cs @@ -492,5 +492,215 @@ namespace System.Tests Assert.Throws(() => d.ToString("Y")); // Invalid format Assert.Throws(() => 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 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 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)); + } } } diff --git a/src/libraries/System.Runtime/tests/System/DoubleTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/DoubleTests.netcoreapp.cs deleted file mode 100644 index 056145b..0000000 --- a/src/libraries/System.Runtime/tests/System/DoubleTests.netcoreapp.cs +++ /dev/null @@ -1,226 +0,0 @@ -// 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 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 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)); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/EnumTests.cs b/src/libraries/System.Runtime/tests/System/EnumTests.cs index ca353e2..2d4d385 100644 --- a/src/libraries/System.Runtime/tests/System/EnumTests.cs +++ b/src/libraries/System.Runtime/tests/System/EnumTests.cs @@ -5,11 +5,12 @@ 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 Parse_TestData() { @@ -130,12 +131,14 @@ namespace System.Tests Assert.Equal(expected, result); Assert.Equal(expected, Enum.Parse(expected.GetType(), value)); + Assert.Equal(expected, Enum.Parse(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(value, ignoreCase)); } public static IEnumerable Parse_Invalid_TestData() @@ -226,19 +229,35 @@ namespace System.Tests private static void Parse_Generic_Invalid(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(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(value, ignoreCase)); + } + else + { + Assert.Throws(exceptionType, () => Enum.TryParse(enumType, value, ignoreCase, out result)); + Assert.Equal(default(object), result); + } } public static IEnumerable GetName_TestData() @@ -1589,5 +1608,155 @@ namespace System.Tests Assert.Throws(() => Enum.Format(typeof(SimpleEnum), SimpleEnum.Red, " \t")); // Format is whitespace Assert.Throws(() => Enum.Format(typeof(SimpleEnum), SimpleEnum.Red, "t")); // No such format } + + public static IEnumerable 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(); +#endif + } + + [Theory] + [MemberData(nameof(UnsupportedEnumType_TestData))] + public static void GetName_Unsupported_ThrowsArgumentException(Type enumType, object value) + { + AssertExtensions.Throws("value", () => Enum.GetName(enumType, value)); + } + + [Theory] + [MemberData(nameof(UnsupportedEnumType_TestData))] + public static void IsDefined_UnsupportedEnumType_ThrowsInvalidOperationException(Type enumType, object value) + { + Exception ex = Assert.ThrowsAny(() => Enum.IsDefined(enumType, value)); + string exName = ex.GetType().Name; + Assert.True(exName == nameof(InvalidOperationException) || exName == "ContractException"); + } + + public static IEnumerable 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(() => 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(() => Enum.Format(enumType, value, "G")); + string formatGExceptionName = formatGException.GetType().Name; + Assert.True(formatGExceptionName == nameof(InvalidOperationException) || formatGExceptionName == "ContractException"); + + Exception formatXException = Assert.ThrowsAny(() => Enum.Format(enumType, value, "X")); + string formatXExceptionName = formatXException.GetType().Name; + Assert.True(formatXExceptionName == nameof(InvalidOperationException) || formatXExceptionName == "ContractException"); + + Exception formatFException = Assert.ThrowsAny(() => 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(); + } } } diff --git a/src/libraries/System.Runtime/tests/System/EnumTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/EnumTests.netcoreapp.cs deleted file mode 100644 index 51fd0f5..0000000 --- a/src/libraries/System.Runtime/tests/System/EnumTests.netcoreapp.cs +++ /dev/null @@ -1,229 +0,0 @@ -// 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(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(value)); - } - - Assert.True(Enum.TryParse(expected.GetType(), value, ignoreCase, out result)); - Assert.Equal(expected, result); - - Assert.Equal(expected, Enum.Parse(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(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(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(value, ignoreCase)); - } - else - { - Assert.Throws(exceptionType, () => Enum.TryParse(enumType, value, ignoreCase, out result)); - Assert.Equal(default(object), result); - } - } - - public static IEnumerable 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(); -#endif - } - - [Theory] - [MemberData(nameof(UnsupportedEnumType_TestData))] - public static void GetName_Unsupported_ThrowsArgumentException(Type enumType, object value) - { - AssertExtensions.Throws("value", () => Enum.GetName(enumType, value)); - } - - [Theory] - [MemberData(nameof(UnsupportedEnumType_TestData))] - public static void IsDefined_UnsupportedEnumType_ThrowsInvalidOperationException(Type enumType, object value) - { - Exception ex = Assert.ThrowsAny(() => Enum.IsDefined(enumType, value)); - string exName = ex.GetType().Name; - Assert.True(exName == nameof(InvalidOperationException) || exName == "ContractException"); - } - - public static IEnumerable 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(); -#endif - } - - [Theory] - [MemberData(nameof(UnsupportedEnum_TestData))] - public static void ToString_UnsupportedEnumType_ThrowsArgumentException(Enum e) - { - Exception formatXException = Assert.ThrowsAny(() => 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(() => Enum.Format(enumType, value, "G")); - string formatGExceptionName = formatGException.GetType().Name; - Assert.True(formatGExceptionName == nameof(InvalidOperationException) || formatGExceptionName == "ContractException"); - - Exception formatXException = Assert.ThrowsAny(() => Enum.Format(enumType, value, "X")); - string formatXExceptionName = formatXException.GetType().Name; - Assert.True(formatXExceptionName == nameof(InvalidOperationException) || formatXExceptionName == "ContractException"); - - Exception formatFException = Assert.ThrowsAny(() => 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(); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/FormattableStringTests.cs b/src/libraries/System.Runtime/tests/System/FormattableStringTests.cs index d8c1a49..8faa9ec 100644 --- a/src/libraries/System.Runtime/tests/System/FormattableStringTests.cs +++ b/src/libraries/System.Runtime/tests/System/FormattableStringTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace System.Tests { - public partial class FormattableStringTests + public class FormattableStringTests { [Fact] public static void Invariant_Null_ThrowsArgumentNullException() @@ -50,5 +50,32 @@ namespace System.Tests } } + [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("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); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/FormattableStringTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/FormattableStringTests.netcoreapp.cs deleted file mode 100644 index f87b454..0000000 --- a/src/libraries/System.Runtime/tests/System/FormattableStringTests.netcoreapp.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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("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); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/GCTests.cs b/src/libraries/System.Runtime/tests/System/GCTests.cs index 6ae1d76..e501284 100644 --- a/src/libraries/System.Runtime/tests/System/GCTests.cs +++ b/src/libraries/System.Runtime/tests/System/GCTests.cs @@ -2,7 +2,9 @@ // 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; @@ -11,7 +13,7 @@ using Xunit; 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 @@ -762,5 +764,130 @@ namespace System.Tests 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); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/GCTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/GCTests.netcoreapp.cs deleted file mode 100644 index f2bd13a..0000000 --- a/src/libraries/System.Runtime/tests/System/GCTests.netcoreapp.cs +++ /dev/null @@ -1,139 +0,0 @@ -// 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); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/GuidTests.cs b/src/libraries/System.Runtime/tests/System/GuidTests.cs index ac04a5a..1cd179b 100644 --- a/src/libraries/System.Runtime/tests/System/GuidTests.cs +++ b/src/libraries/System.Runtime/tests/System/GuidTests.cs @@ -9,7 +9,7 @@ using Xunit; 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); @@ -761,5 +761,120 @@ namespace System.Tests { 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(b))); + } + + [Theory] + [InlineData(15)] + [InlineData(17)] + public static void CtorSpan_InvalidLengthByteArray_ThrowsArgumentException(int length) + { + AssertExtensions.Throws("b", null, () => new Guid(new ReadOnlySpan(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(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(new byte[length]))); + } + + [Theory] + [MemberData(nameof(InvalidFormat_TestData))] + public static void TryFormat_InvalidFormat_ThrowsFormatException(string format) + { + Assert.Throws(() => s_testGuid.TryFormat(new Span(), out int charsWritten, format)); + Assert.Throws(() => s_testGuid.TryFormat(new Span(), 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(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(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(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); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/GuidTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/GuidTests.netcoreapp.cs deleted file mode 100644 index 83faf85..0000000 --- a/src/libraries/System.Runtime/tests/System/GuidTests.netcoreapp.cs +++ /dev/null @@ -1,126 +0,0 @@ -// 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(b))); - } - - [Theory] - [InlineData(15)] - [InlineData(17)] - public static void CtorSpan_InvalidLengthByteArray_ThrowsArgumentException(int length) - { - AssertExtensions.Throws("b", null, () => new Guid(new ReadOnlySpan(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(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(new byte[length]))); - } - - [Theory] - [MemberData(nameof(InvalidFormat_TestData))] - public static void TryFormat_InvalidFormat_ThrowsFormatException(string format) - { - Assert.Throws(() => s_testGuid.TryFormat(new Span(), out int charsWritten, format)); - Assert.Throws(() => s_testGuid.TryFormat(new Span(), 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(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(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(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); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/HashCodeTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/HashCodeTests.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/HashCodeTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/HashCodeTests.cs diff --git a/src/libraries/System.Runtime/tests/System/Int16Tests.cs b/src/libraries/System.Runtime/tests/System/Int16Tests.cs index 1264754..46b286d 100644 --- a/src/libraries/System.Runtime/tests/System/Int16Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int16Tests.cs @@ -8,7 +8,7 @@ using Xunit; namespace System.Tests { - public partial class Int16Tests + public class Int16Tests { [Fact] public static void Ctor_Empty() @@ -314,5 +314,106 @@ namespace System.Tests AssertExtensions.Throws(paramName, () => short.Parse("1", style)); AssertExtensions.Throws(paramName, () => short.Parse("1", style, null)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/Int16Tests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Int16Tests.netcoreapp.cs deleted file mode 100644 index c2ad54c..0000000 --- a/src/libraries/System.Runtime/tests/System/Int16Tests.netcoreapp.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Int32Tests.cs b/src/libraries/System.Runtime/tests/System/Int32Tests.cs index dd62439..2a338f0 100644 --- a/src/libraries/System.Runtime/tests/System/Int32Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int32Tests.cs @@ -8,7 +8,7 @@ using Xunit; namespace System.Tests { - public partial class Int32Tests + public class Int32Tests { [Fact] public static void Ctor_Empty() @@ -677,5 +677,153 @@ namespace System.Tests nfi.CurrencySymbol = "$"; Assert.Equal("$1234", 1234.ToString("C0", nfi)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/Int32Tests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Int32Tests.netcoreapp.cs deleted file mode 100644 index 086744b..0000000 --- a/src/libraries/System.Runtime/tests/System/Int32Tests.netcoreapp.cs +++ /dev/null @@ -1,161 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Int64Tests.cs b/src/libraries/System.Runtime/tests/System/Int64Tests.cs index 2d31151..d005869 100644 --- a/src/libraries/System.Runtime/tests/System/Int64Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int64Tests.cs @@ -9,7 +9,7 @@ using Xunit; namespace System.Tests { - public partial class Int64Tests + public class Int64Tests { [Fact] public static void Ctor_Empty() @@ -330,5 +330,104 @@ namespace System.Tests AssertExtensions.Throws(paramName, () => long.Parse("1", style)); AssertExtensions.Throws(paramName, () => long.Parse("1", style, null)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/Int64Tests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Int64Tests.netcoreapp.cs deleted file mode 100644 index 8a7bc04..0000000 --- a/src/libraries/System.Runtime/tests/System/Int64Tests.netcoreapp.cs +++ /dev/null @@ -1,112 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs index 31828f1..dca7832 100644 --- a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs @@ -8,7 +8,7 @@ using Xunit; namespace System.Tests { - public static partial class IntPtrTests + public static class IntPtrTests { private static unsafe bool Is64Bit => sizeof(void*) == 8; @@ -116,6 +116,9 @@ namespace System.Tests Assert.Equal(expected, ptr1 == ptr2); Assert.Equal(!expected, ptr1 != ptr2); Assert.Equal(expected, ptr1.GetHashCode().Equals(ptr2.GetHashCode())); + + IEquatable iEquatable = ptr1; + Assert.Equal(expected, iEquatable.Equals((IntPtr)obj)); } Assert.Equal(expected, ptr1.Equals(obj)); Assert.Equal(ptr1.GetHashCode(), ptr1.GetHashCode()); diff --git a/src/libraries/System.Runtime/tests/System/IntPtrTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/IntPtrTests.netcoreapp.cs deleted file mode 100644 index d7497e6..0000000 --- a/src/libraries/System.Runtime/tests/System/IntPtrTests.netcoreapp.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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 iEquatable = ptr; - Assert.Equal(expected, iEquatable.Equals((IntPtr)obj)); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/LazyTests.cs b/src/libraries/System.Runtime/tests/System/LazyTests.cs index 0736195..f2ccfdd 100644 --- a/src/libraries/System.Runtime/tests/System/LazyTests.cs +++ b/src/libraries/System.Runtime/tests/System/LazyTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace System.Tests { - public static partial class LazyTests + public static class LazyTests { [Fact] public static void Ctor() @@ -535,6 +535,49 @@ namespace System.Tests Assert.Equal(template, d); } + [Fact] + public static void Ctor_Value_ReferenceType() + { + var lazyString = new Lazy("abc"); + VerifyLazy(lazyString, "abc", hasValue: true, isValueCreated: true); + } + + [Fact] + public static void Ctor_Value_ValueType() + { + var lazyObject = new Lazy(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(() => LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => null)); + } private static void VerifyLazy(Lazy lazy, T expectedValue, bool hasValue, bool isValueCreated) { Assert.Equal(isValueCreated, lazy.IsValueCreated); diff --git a/src/libraries/System.Runtime/tests/System/LazyTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/LazyTests.netcoreapp.cs deleted file mode 100644 index bb85e8f..0000000 --- a/src/libraries/System.Runtime/tests/System/LazyTests.netcoreapp.cs +++ /dev/null @@ -1,56 +0,0 @@ -// 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("abc"); - VerifyLazy(lazyString, "abc", hasValue: true, isValueCreated: true); - } - - [Fact] - public static void Ctor_Value_ValueType() - { - var lazyObject = new Lazy(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(() => LazyInitializer.EnsureInitialized(ref target, ref syncLock, () => null)); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/RealFormatterTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/RealFormatterTests.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/RealFormatterTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/RealFormatterTests.cs diff --git a/src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.cs diff --git a/src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.cs diff --git a/src/libraries/System.Runtime/tests/System/Reflection/MethodBaseTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/MethodBaseTests.cs index a2cce63..0883838 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/MethodBaseTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/MethodBaseTests.cs @@ -23,19 +23,6 @@ namespace System.Reflection.Tests } [Fact] - public static void Test_GetCurrentMethod_GenericMethodDefinition() - { - MethodBase m = MyFakeGenericMethod(); - - 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() { // Verify that the result is not affected by inlining optimizations @@ -91,12 +78,6 @@ namespace System.Reflection.Tests #endif } - public static MethodBase MyFakeGenericMethod() - { - MethodBase m = MethodBase.GetCurrentMethod(); - return m; - } - private static int MyAnotherMethod(int x) { return x+1; @@ -119,5 +100,38 @@ namespace System.Reflection.Tests } } #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() + { + } } } diff --git a/src/libraries/System.Runtime/tests/System/Reflection/MethodBaseTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Reflection/MethodBaseTests.netcoreapp.cs deleted file mode 100644 index 643e372..0000000 --- a/src/libraries/System.Runtime/tests/System/Reflection/MethodBaseTests.netcoreapp.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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() - { - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Reflection/SignatureTypes.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Reflection/SignatureTypes.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/Reflection/SignatureTypes.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Reflection/SignatureTypes.cs diff --git a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs index 9ac2711..1c03661 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs @@ -2,6 +2,7 @@ // 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 @@ -42,5 +43,42 @@ namespace System.Reflection.Tests Assert.True(new TypeDelegator(typeof(TypeCode)).IsValueType); Assert.True(new TypeDelegator(typeof(TypeCode)).IsEnum); } + + public static IEnumerable 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.Inside), false }; + yield return new object[] { typeof(Outside.Inside[]), true }; + yield return new object[] { typeof(Outside.Inside[,]), false }; + if (PlatformDetection.IsNonZeroLowerBoundArraySupported) + { + yield return new object[] { Array.CreateInstance(typeof(Outside.Inside), new[] { 2 }, new[] { -1 }).GetType(), false }; + } + } + + [Theory, MemberData(nameof(SZArrayOrNotTypes))] + public void IsSZArray(Type type, bool expected) + { + Assert.Equal(expected, new TypeDelegator(type).IsSZArray); + } } } diff --git a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.netcoreapp.cs deleted file mode 100644 index 8009dc9..0000000 --- a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.netcoreapp.cs +++ /dev/null @@ -1,49 +0,0 @@ -// 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 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.Inside), false }; - yield return new object[] { typeof(Outside.Inside[]), true }; - yield return new object[] { typeof(Outside.Inside[,]), false }; - if (PlatformDetection.IsNonZeroLowerBoundArraySupported) - { - yield return new object[] { Array.CreateInstance(typeof(Outside.Inside), new[] { 2 }, new[] { -1 }).GetType(), false }; - } - } - - [Theory, MemberData(nameof(SZArrayOrNotTypes))] - public void IsSZArray(Type type, bool expected) - { - Assert.Equal(expected, new TypeDelegator(type).IsSZArray); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs index c1d141f..66ba84f 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs @@ -6,7 +6,7 @@ using Xunit; namespace System.Runtime.CompilerServices.Tests { - public static partial class AttributesTests + public static class AttributesTests { [Fact] public static void AccessedThroughPropertyAttributeTests() @@ -252,5 +252,33 @@ namespace System.Runtime.CompilerServices.Tests { 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(); + } } } diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.netcoreapp.cs deleted file mode 100644 index 089b81d..0000000 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.netcoreapp.cs +++ /dev/null @@ -1,39 +0,0 @@ -// 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(); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/ConditionalWeakTableTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/ConditionalWeakTableTests.cs index c7964cd..069826a 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/ConditionalWeakTableTests.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/ConditionalWeakTableTests.cs @@ -2,14 +2,17 @@ // 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() @@ -318,5 +321,285 @@ namespace System.Runtime.CompilerServices.Tests // 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 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(() => 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(); + cwt.Clear(); // no exception + cwt.Clear(); + } + + [Fact] + public static void Clear_AddThenEmptyRepeatedly_ItemsRemoved() + { + var cwt = new ConditionalWeakTable(); + 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[] 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>)cwt).Count()); + + cwt.Clear(); + + Assert.Equal(0, ((IEnumerable>)cwt).Count()); + + GC.KeepAlive(keys); + GC.KeepAlive(values); + } + + [Fact] + public static void GetEnumerator_Empty_ReturnsEmptyEnumerator() + { + var cwt = new ConditionalWeakTable(); + var enumerable = (IEnumerable>)cwt; + Assert.Equal(0, enumerable.Count()); + } + + [Fact] + public static void GetEnumerator_AddedAndRemovedItems_AppropriatelyShowUpInEnumeration() + { + var cwt = new ConditionalWeakTable(); + var enumerable = (IEnumerable>)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(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(); + var enumerable = (IEnumerable>)cwt; + + // Delegate to add collectible items to the table, separated out + // to avoid the JIT extending the lifetimes of the temporaries + Action> 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(); + var enumerable = (IEnumerable>)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> enumerator1 = enumerable.GetEnumerator()) + using (IEnumerator> 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(); + var enumerable = (IEnumerable>)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(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(); + var enumerable = (IEnumerable>)cwt; + + object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object(); + + cwt.Add(key1, value1); + IEnumerator> enumerator1 = enumerable.GetEnumerator(); + cwt.Add(key2, value2); + IEnumerator> enumerator2 = enumerable.GetEnumerator(); + + Assert.True(enumerator1.MoveNext()); + Assert.Equal(new KeyValuePair(key1, value1), enumerator1.Current); + Assert.False(enumerator1.MoveNext()); + + Assert.True(enumerator2.MoveNext()); + Assert.Equal(new KeyValuePair(key1, value1), enumerator2.Current); + Assert.True(enumerator2.MoveNext()); + Assert.Equal(new KeyValuePair(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(); + var enumerable = (IEnumerable>)cwt; + + object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object(); + + cwt.Add(key1, value1); + cwt.Add(key2, value2); + IEnumerator> enumerator1 = enumerable.GetEnumerator(); + cwt.Remove(key1); + IEnumerator> enumerator2 = enumerable.GetEnumerator(); + + Assert.True(enumerator1.MoveNext()); + Assert.Equal(new KeyValuePair(key2, value2), enumerator1.Current); + Assert.False(enumerator1.MoveNext()); + + Assert.True(enumerator2.MoveNext()); + Assert.Equal(new KeyValuePair(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(); + var enumerable = (IEnumerable>)cwt; + + object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object(); + + cwt.Add(key1, value1); + cwt.Add(key2, value2); + IEnumerator> enumerator1 = enumerable.GetEnumerator(); + cwt.Clear(); + IEnumerator> 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(); + var enumerable = (IEnumerable>)cwt; + + object key1 = new object(), value1 = new object(); + cwt.Add(key1, value1); + + using (IEnumerator> enumerator = enumerable.GetEnumerator()) + { + Assert.Throws(() => enumerator.Current); // before first MoveNext + } + + GC.KeepAlive(key1); + GC.KeepAlive(value1); + } } } diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/ConditionalWeakTableTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/ConditionalWeakTableTests.netcoreapp.cs deleted file mode 100644 index ca44f62..0000000 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/ConditionalWeakTableTests.netcoreapp.cs +++ /dev/null @@ -1,295 +0,0 @@ -// 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 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(() => 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(); - cwt.Clear(); // no exception - cwt.Clear(); - } - - [Fact] - public static void Clear_AddThenEmptyRepeatedly_ItemsRemoved() - { - var cwt = new ConditionalWeakTable(); - 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[] 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>)cwt).Count()); - - cwt.Clear(); - - Assert.Equal(0, ((IEnumerable>)cwt).Count()); - - GC.KeepAlive(keys); - GC.KeepAlive(values); - } - - [Fact] - public static void GetEnumerator_Empty_ReturnsEmptyEnumerator() - { - var cwt = new ConditionalWeakTable(); - var enumerable = (IEnumerable>)cwt; - Assert.Equal(0, enumerable.Count()); - } - - [Fact] - public static void GetEnumerator_AddedAndRemovedItems_AppropriatelyShowUpInEnumeration() - { - var cwt = new ConditionalWeakTable(); - var enumerable = (IEnumerable>)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(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(); - var enumerable = (IEnumerable>)cwt; - - // Delegate to add collectible items to the table, separated out - // to avoid the JIT extending the lifetimes of the temporaries - Action> 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(); - var enumerable = (IEnumerable>)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> enumerator1 = enumerable.GetEnumerator()) - using (IEnumerator> 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(); - var enumerable = (IEnumerable>)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(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(); - var enumerable = (IEnumerable>)cwt; - - object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object(); - - cwt.Add(key1, value1); - IEnumerator> enumerator1 = enumerable.GetEnumerator(); - cwt.Add(key2, value2); - IEnumerator> enumerator2 = enumerable.GetEnumerator(); - - Assert.True(enumerator1.MoveNext()); - Assert.Equal(new KeyValuePair(key1, value1), enumerator1.Current); - Assert.False(enumerator1.MoveNext()); - - Assert.True(enumerator2.MoveNext()); - Assert.Equal(new KeyValuePair(key1, value1), enumerator2.Current); - Assert.True(enumerator2.MoveNext()); - Assert.Equal(new KeyValuePair(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(); - var enumerable = (IEnumerable>)cwt; - - object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object(); - - cwt.Add(key1, value1); - cwt.Add(key2, value2); - IEnumerator> enumerator1 = enumerable.GetEnumerator(); - cwt.Remove(key1); - IEnumerator> enumerator2 = enumerable.GetEnumerator(); - - Assert.True(enumerator1.MoveNext()); - Assert.Equal(new KeyValuePair(key2, value2), enumerator1.Current); - Assert.False(enumerator1.MoveNext()); - - Assert.True(enumerator2.MoveNext()); - Assert.Equal(new KeyValuePair(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(); - var enumerable = (IEnumerable>)cwt; - - object key1 = new object(), key2 = new object(), value1 = new object(), value2 = new object(); - - cwt.Add(key1, value1); - cwt.Add(key2, value2); - IEnumerator> enumerator1 = enumerable.GetEnumerator(); - cwt.Clear(); - IEnumerator> 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(); - var enumerable = (IEnumerable>)cwt; - - object key1 = new object(), value1 = new object(); - cwt.Add(key1, value1); - - using (IEnumerator> enumerator = enumerable.GetEnumerator()) - { - Assert.Throws(() => enumerator.Current); // before first MoveNext - } - - GC.KeepAlive(key1); - GC.KeepAlive(value1); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/MethodImplAttributeTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/MethodImplAttributeTests.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/MethodImplAttributeTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/MethodImplAttributeTests.cs diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeFeatureTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeFeatureTests.cs similarity index 95% rename from src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeFeatureTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeFeatureTests.cs index 36f9f365..2177169 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeFeatureTests.netcoreapp.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeFeatureTests.cs @@ -8,7 +8,7 @@ using Xunit; namespace System.Runtime.CompilerServices.Tests { - public static partial class RuntimeFeatureTests + public static class RuntimeFeatureTests { [Fact] public static void PortablePdb() diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs index 266196a..bd4054d 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs @@ -7,11 +7,12 @@ using System.Reflection; 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() @@ -178,30 +179,104 @@ namespace System.Runtime.CompilerServices.Tests RuntimeHelpers.PrepareDelegate((Func)(() => 1) + (Func)(() => 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(() => RuntimeHelpers.EnsureSufficientExecutionStack()); + return; + } + else if (depth < 2048) + { + FillStack(depth + 1); } } - } - public static partial class RuntimeHelpersTests - { + [Fact] + public static void GetUninitializedObject_InvalidArguments_ThrowsException() + { + AssertExtensions.Throws("type", () => RuntimeHelpers.GetUninitializedObject(null)); + + AssertExtensions.Throws(null, () => RuntimeHelpers.GetUninitializedObject(typeof(string))); // special type + Assert.Throws(() => RuntimeHelpers.GetUninitializedObject(typeof(System.IO.Stream))); // abstract type + Assert.Throws(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.IEnumerable))); // interface + Assert.Throws(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.Generic.List<>))); // generic definition + Assert.Throws(() => 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)).GetType()); + } + + private class ObjectWithDefaultCtor + { + public int Value = 42; + } + + [Fact] + public static void IsReferenceOrContainsReferences() + { + Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences()); + Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences()); + Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences()); + Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences()); + Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences()); + } + + [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(() => { 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() { @@ -218,4 +293,24 @@ namespace System.Runtime.CompilerServices.Tests 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; + } + } + } } diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.netcoreapp.cs deleted file mode 100644 index 3c71a58..0000000 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.netcoreapp.cs +++ /dev/null @@ -1,110 +0,0 @@ -// 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(() => RuntimeHelpers.EnsureSufficientExecutionStack()); - return; - } - else if (depth < 2048) - { - FillStack(depth + 1); - } - } - - [Fact] - public static void GetUninitializedObject_InvalidArguments_ThrowsException() - { - AssertExtensions.Throws("type", () => RuntimeHelpers.GetUninitializedObject(null)); - - AssertExtensions.Throws(null, () => RuntimeHelpers.GetUninitializedObject(typeof(string))); // special type - Assert.Throws(() => RuntimeHelpers.GetUninitializedObject(typeof(System.IO.Stream))); // abstract type - Assert.Throws(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.IEnumerable))); // interface - Assert.Throws(() => RuntimeHelpers.GetUninitializedObject(typeof(System.Collections.Generic.List<>))); // generic definition - Assert.Throws(() => 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)).GetType()); - } - - private class ObjectWithDefaultCtor - { - public int Value = 42; - } - - [Fact] - public static void IsReferenceOrContainsReferences() - { - Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences()); - Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences()); - Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences()); - Assert.False(RuntimeHelpers.IsReferenceOrContainsReferences()); - Assert.True(RuntimeHelpers.IsReferenceOrContainsReferences()); - } - - [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(() => { 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; - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.cs similarity index 98% rename from src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.cs index f9b18bf..de28c30 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.netcoreapp.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace System.Runtime.ExceptionServices.Tests { - public partial class ExceptionDispatchInfoTests + public class ExceptionDispatchInfoTests { [Fact] public static void StaticThrow_NullArgument_ThrowArgumentNullException() diff --git a/src/libraries/System.Runtime/tests/System/SByteTests.cs b/src/libraries/System.Runtime/tests/System/SByteTests.cs index 439b5a2..3256c29 100644 --- a/src/libraries/System.Runtime/tests/System/SByteTests.cs +++ b/src/libraries/System.Runtime/tests/System/SByteTests.cs @@ -309,5 +309,104 @@ namespace System.Tests AssertExtensions.Throws(paramName, () => sbyte.Parse("1", style)); AssertExtensions.Throws(paramName, () => sbyte.Parse("1", style, null)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/SByteTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/SByteTests.netcoreapp.cs deleted file mode 100644 index 513b9b5..0000000 --- a/src/libraries/System.Runtime/tests/System/SByteTests.netcoreapp.cs +++ /dev/null @@ -1,112 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/SingleTests.cs b/src/libraries/System.Runtime/tests/System/SingleTests.cs index b7c6bf9..a030d0c 100644 --- a/src/libraries/System.Runtime/tests/System/SingleTests.cs +++ b/src/libraries/System.Runtime/tests/System/SingleTests.cs @@ -491,5 +491,218 @@ namespace System.Tests Assert.Throws(() => f.ToString("Y")); // Invalid format Assert.Throws(() => 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 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 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)); + } } } diff --git a/src/libraries/System.Runtime/tests/System/SingleTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/SingleTests.netcoreapp.cs deleted file mode 100644 index 22423d4..0000000 --- a/src/libraries/System.Runtime/tests/System/SingleTests.netcoreapp.cs +++ /dev/null @@ -1,229 +0,0 @@ -// 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 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 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)); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/StringComparerTests.cs b/src/libraries/System.Runtime/tests/System/StringComparerTests.cs index d3ef247..08bdba5 100644 --- a/src/libraries/System.Runtime/tests/System/StringComparerTests.cs +++ b/src/libraries/System.Runtime/tests/System/StringComparerTests.cs @@ -7,7 +7,7 @@ using Xunit; namespace System.Tests { - public partial class StringComparerTests + public class StringComparerTests { [Fact] public void Create_InvalidArguments_Throws() @@ -109,5 +109,32 @@ namespace System.Tests Assert.False(c.Equals("42", 84)); Assert.False(c.Equals(42, "84")); } + + [Fact] + public void CreateCultureOptions_InvalidArguments_Throws() + { + Assert.Throws(() => 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(() => c.Compare("42", 84)); + Assert.Equal(1, c.Compare("42", null)); + Assert.Throws(() => c.Compare(42, "84")); + } } } diff --git a/src/libraries/System.Runtime/tests/System/StringComparerTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/StringComparerTests.netcoreapp.cs deleted file mode 100644 index a31986c..0000000 --- a/src/libraries/System.Runtime/tests/System/StringComparerTests.netcoreapp.cs +++ /dev/null @@ -1,39 +0,0 @@ -// 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(() => 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(() => c.Compare("42", 84)); - Assert.Equal(1, c.Compare("42", null)); - Assert.Throws(() => c.Compare(42, "84")); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/StringGetHashCodeTests.cs b/src/libraries/System.Runtime/tests/System/StringGetHashCodeTests.cs index ce4f672..82dbbb4 100644 --- a/src/libraries/System.Runtime/tests/System/StringGetHashCodeTests.cs +++ b/src/libraries/System.Runtime/tests/System/StringGetHashCodeTests.cs @@ -10,7 +10,7 @@ using Xunit; namespace System.Tests { - public partial class StringGetHashCodeTests + public class StringGetHashCodeTests { /// /// Ensure that hash codes are randomized by getting the hash in two processes @@ -61,5 +61,44 @@ namespace System.Tests () => { 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 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 + } } } diff --git a/src/libraries/System.Runtime/tests/System/StringGetHashCodeTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/StringGetHashCodeTests.netcoreapp.cs deleted file mode 100644 index f3479d3..0000000 --- a/src/libraries/System.Runtime/tests/System/StringGetHashCodeTests.netcoreapp.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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 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 - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/StringTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/StringTests.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/StringTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/StringTests.cs diff --git a/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs similarity index 99% rename from src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs index 638c131..d224888 100644 --- a/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.netcoreapp.cs +++ b/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs @@ -13,7 +13,7 @@ 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 + public static unsafe class AsciiUtilityTests { private const int SizeOfVector128 = 128 / 8; diff --git a/src/libraries/System.Runtime/tests/System/Text/RuneTests.TestData.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/RuneTests.TestData.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/Text/RuneTests.TestData.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Text/RuneTests.TestData.cs diff --git a/src/libraries/System.Runtime/tests/System/Text/RuneTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/RuneTests.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/Text/RuneTests.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Text/RuneTests.cs diff --git a/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs b/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs index d6d9388..7862302 100644 --- a/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs +++ b/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.Linq; using System.Tests; using Microsoft.DotNet.RemoteExecutor; using Xunit; @@ -1782,5 +1783,453 @@ namespace System.Text.Tests 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("values", () => new StringBuilder().AppendJoin('|', (object[])null)); + AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin('|', (IEnumerable)null)); + AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin('|', (string[])null)); + AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin("|", (object[])null)); + AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin("|", (IEnumerable)null)); + AssertExtensions.Throws("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(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values)); + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable)); + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues)); + } + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values)); + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable)); + AssertExtensions.Throws(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(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(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(destination), destination.Length); + Assert.Equal(s_chunkSplitSource.ToCharArray(), destination); + } + + [Fact] + public static void CopyTo_CharSpan_Invalid() + { + var builder = new StringBuilder("Hello"); + + AssertExtensions.Throws("sourceIndex", () => builder.CopyTo(-1, new Span(new char[10]), 0)); // Source index < 0 + AssertExtensions.Throws("sourceIndex", () => builder.CopyTo(6, new Span(new char[10]), 0)); // Source index > builder.Length + + AssertExtensions.Throws("count", () => builder.CopyTo(0, new Span(new char[10]), -1)); // Count < 0 + + AssertExtensions.Throws(null, () => builder.CopyTo(5, new Span(new char[10]), 1)); // Source index + count > builder.Length + AssertExtensions.Throws(null, () => builder.CopyTo(4, new Span(new char[10]), 2)); // Source index + count > builder.Length + + AssertExtensions.Throws(null, () => builder.CopyTo(0, new Span(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(value)); + Assert.Equal(expected, builder.ToString()); + } + + [Fact] + public static void Insert_CharSpan_Invalid() + { + var builder = new StringBuilder(0, 5); + builder.Append("Hello"); + + AssertExtensions.Throws("index", () => builder.Insert(-1, new ReadOnlySpan(new char[0]))); // Index < 0 + AssertExtensions.Throws("index", () => builder.Insert(builder.Length + 1, new ReadOnlySpan(new char[0]))); // Index > builder.Length + AssertExtensions.Throws("requiredLength", () => builder.Insert(builder.Length, new ReadOnlySpan(new char[1]))); // New length > builder.MaxCapacity + } + + public static IEnumerable 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 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(() => sb.Append(sb, -1, 0)); + Assert.Throws(() => sb.Append(sb, 0, -1)); + Assert.Throws(() => sb.Append(sb, 4, 5)); + + Assert.Throws(() => sb.Append( (StringBuilder)null, 2, 2)); + Assert.Throws(() => sb.Append((StringBuilder)null, 2, 3)); + Assert.Throws(() => new StringBuilder(3, 6).Append("Hello").Append(sb)); + Assert.Throws(() => new StringBuilder(3, 6).Append("Hello").Append("Hello")); + + Assert.Throws(() => sb.Append(sb)); + } + + public static IEnumerable 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 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)); + } } } diff --git a/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs deleted file mode 100644 index e854c3c..0000000 --- a/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs +++ /dev/null @@ -1,462 +0,0 @@ -// 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("values", () => new StringBuilder().AppendJoin('|', (object[])null)); - AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin('|', (IEnumerable)null)); - AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin('|', (string[])null)); - AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin("|", (object[])null)); - AssertExtensions.Throws("values", () => new StringBuilder().AppendJoin("|", (IEnumerable)null)); - AssertExtensions.Throws("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(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values)); - AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable)); - AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues)); - } - AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values)); - AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable)); - AssertExtensions.Throws(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(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(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(destination), destination.Length); - Assert.Equal(s_chunkSplitSource.ToCharArray(), destination); - } - - [Fact] - public static void CopyTo_CharSpan_Invalid() - { - var builder = new StringBuilder("Hello"); - - AssertExtensions.Throws("sourceIndex", () => builder.CopyTo(-1, new Span(new char[10]), 0)); // Source index < 0 - AssertExtensions.Throws("sourceIndex", () => builder.CopyTo(6, new Span(new char[10]), 0)); // Source index > builder.Length - - AssertExtensions.Throws("count", () => builder.CopyTo(0, new Span(new char[10]), -1)); // Count < 0 - - AssertExtensions.Throws(null, () => builder.CopyTo(5, new Span(new char[10]), 1)); // Source index + count > builder.Length - AssertExtensions.Throws(null, () => builder.CopyTo(4, new Span(new char[10]), 2)); // Source index + count > builder.Length - - AssertExtensions.Throws(null, () => builder.CopyTo(0, new Span(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(value)); - Assert.Equal(expected, builder.ToString()); - } - - [Fact] - public static void Insert_CharSpan_Invalid() - { - var builder = new StringBuilder(0, 5); - builder.Append("Hello"); - - AssertExtensions.Throws("index", () => builder.Insert(-1, new ReadOnlySpan(new char[0]))); // Index < 0 - AssertExtensions.Throws("index", () => builder.Insert(builder.Length + 1, new ReadOnlySpan(new char[0]))); // Index > builder.Length - AssertExtensions.Throws("requiredLength", () => builder.Insert(builder.Length, new ReadOnlySpan(new char[1]))); // New length > builder.MaxCapacity - } - - public static IEnumerable 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 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(() => sb.Append(sb, -1, 0)); - Assert.Throws(() => sb.Append(sb, 0, -1)); - Assert.Throws(() => sb.Append(sb, 4, 5)); - - Assert.Throws(() => sb.Append( (StringBuilder)null, 2, 2)); - Assert.Throws(() => sb.Append((StringBuilder)null, 2, 3)); - Assert.Throws(() => new StringBuilder(3, 6).Append("Hello").Append(sb)); - Assert.Throws(() => new StringBuilder(3, 6).Append("Hello").Append("Hello")); - - Assert.Throws(() => sb.Append(sb)); - } - - public static IEnumerable 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 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)); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/UnicodeData.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/UnicodeData.cs similarity index 100% rename from src/libraries/System.Runtime/tests/System/Text/Unicode/UnicodeData.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Text/Unicode/UnicodeData.cs diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs similarity index 99% rename from src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs index cf47587..c719183 100644 --- a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.netcoreapp.cs +++ b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs @@ -12,7 +12,7 @@ using Xunit; namespace System.Text.Unicode.Tests { - public partial class Utf16UtilityTests + public class Utf16UtilityTests { private unsafe delegate char* GetPointerToFirstInvalidCharDel(char* pInputBuffer, int inputLength, out long utf8CodeUnitCountAdjustment, out int scalarCountAdjustment); private static readonly Lazy _getPointerToFirstInvalidCharFn = CreateGetPointerToFirstInvalidCharFn(); diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.ToBytes.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.ToBytes.netcoreapp.cs deleted file mode 100644 index 5432da0..0000000 --- a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.ToBytes.netcoreapp.cs +++ /dev/null @@ -1,304 +0,0 @@ -// 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.Empty); - - int expectedNumCharsConsumed = 0; - byte[] concatenatedUtf8 = Array.Empty(); - - 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.Empty); - } - - [Theory] - [InlineData("", 0, "")] // swapped surrogate pair characters - [InlineData("A", 1, "41")] // consume standalone ASCII char, then swapped surrogate pair characters - [InlineData("AB", 1, "41")] // consume standalone ASCII char, then standalone high surrogate char - [InlineData("AB", 1, "41")] // consume standalone ASCII char, then standalone low surrogate char - [InlineData("AB", 2, "4142")] // consume two ASCII chars, then standalone high surrogate char - [InlineData("AB", 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("", "\uD800").Replace("", "\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("", REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete high surr. - [InlineData("", REPLACEMENT_CHAR_UTF8)] // standalone high surr. and incomplete high surr. - [InlineData("", REPLACEMENT_CHAR_UTF8 + REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete low surr. - [InlineData("ABCD", "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("", "\uD800").Replace("", "\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 + "", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD - [InlineData(E_ACUTE_UTF16 + "", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone low surr. at end - [InlineData(E_ACUTE_UTF16 + "", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD - [InlineData(E_ACUTE_UTF16 + "", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone high surr. at end - [InlineData(E_ACUTE_UTF16 + "", false, 1, OperationStatus.NeedMoreData, E_ACUTE_UTF8)] // don't replace standalone high surr. at end - [InlineData(E_ACUTE_UTF16 + "" + X_UTF16, true, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X' - [InlineData(E_ACUTE_UTF16 + "" + X_UTF16, false, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X' - [InlineData(E_ACUTE_UTF16 + "" + X_UTF16, true, 3, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8 + X_UTF8)] // replacement followed by 'X' - [InlineData(E_ACUTE_UTF16 + "" + 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("", "\uD800").Replace("", "\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 utf16Input, int destinationSize, bool replaceInvalidSequences, bool isFinalChunk, OperationStatus expectedOperationStatus, int expectedNumCharsRead, ReadOnlySpan expectedUtf8Transcoding) - { - // Arrange - - using (BoundedMemory boundedSource = BoundedMemory.AllocateFromExistingData(utf16Input)) - using (BoundedMemory boundedDestination = BoundedMemory.Allocate(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()); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.ToChars.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.cs similarity index 51% rename from src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.ToChars.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.cs index cb39338..b633a50 100644 --- a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.ToChars.netcoreapp.cs +++ b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.cs @@ -3,13 +3,434 @@ // 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 + 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 s_allValidScalars = Enumerable.Range(0x0000, 0xD800).Concat(Enumerable.Range(0xE000, 0x110000 - 0xE000)).Select(value => new Rune(value)); + + private static readonly ReadOnlyMemory s_allScalarsAsUtf16; + private static readonly ReadOnlyMemory s_allScalarsAsUtf8; + + static Utf8Tests() + { + List allScalarsAsUtf16 = new List(); + List allScalarsAsUtf8 = new List(); + + 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 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.Empty); + + int expectedNumCharsConsumed = 0; + byte[] concatenatedUtf8 = Array.Empty(); + + 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.Empty); + } + + [Theory] + [InlineData("", 0, "")] // swapped surrogate pair characters + [InlineData("A", 1, "41")] // consume standalone ASCII char, then swapped surrogate pair characters + [InlineData("AB", 1, "41")] // consume standalone ASCII char, then standalone high surrogate char + [InlineData("AB", 1, "41")] // consume standalone ASCII char, then standalone low surrogate char + [InlineData("AB", 2, "4142")] // consume two ASCII chars, then standalone high surrogate char + [InlineData("AB", 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("", "\uD800").Replace("", "\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("", REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete high surr. + [InlineData("", REPLACEMENT_CHAR_UTF8)] // standalone high surr. and incomplete high surr. + [InlineData("", REPLACEMENT_CHAR_UTF8 + REPLACEMENT_CHAR_UTF8)] // standalone low surr. and incomplete low surr. + [InlineData("ABCD", "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("", "\uD800").Replace("", "\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 + "", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD + [InlineData(E_ACUTE_UTF16 + "", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone low surr. at end + [InlineData(E_ACUTE_UTF16 + "", true, 1, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8)] // not enough output buffer to hold U+FFFD + [InlineData(E_ACUTE_UTF16 + "", true, 2, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // replace standalone high surr. at end + [InlineData(E_ACUTE_UTF16 + "", false, 1, OperationStatus.NeedMoreData, E_ACUTE_UTF8)] // don't replace standalone high surr. at end + [InlineData(E_ACUTE_UTF16 + "" + X_UTF16, true, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X' + [InlineData(E_ACUTE_UTF16 + "" + X_UTF16, false, 2, OperationStatus.DestinationTooSmall, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8)] // not enough output buffer to hold 'X' + [InlineData(E_ACUTE_UTF16 + "" + X_UTF16, true, 3, OperationStatus.Done, E_ACUTE_UTF8 + REPLACEMENT_CHAR_UTF8 + X_UTF8)] // replacement followed by 'X' + [InlineData(E_ACUTE_UTF16 + "" + 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("", "\uD800").Replace("", "\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 utf16Input, int destinationSize, bool replaceInvalidSequences, bool isFinalChunk, OperationStatus expectedOperationStatus, int expectedNumCharsRead, ReadOnlySpan expectedUtf8Transcoding) + { + // Arrange + + using (BoundedMemory boundedSource = BoundedMemory.AllocateFromExistingData(utf16Input)) + using (BoundedMemory boundedDestination = BoundedMemory.Allocate(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 diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.netcoreapp.cs deleted file mode 100644 index f57c769..0000000 --- a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8Tests.netcoreapp.cs +++ /dev/null @@ -1,143 +0,0 @@ -// 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 s_allValidScalars = Enumerable.Range(0x0000, 0xD800).Concat(Enumerable.Range(0xE000, 0x110000 - 0xE000)).Select(value => new Rune(value)); - - private static readonly ReadOnlyMemory s_allScalarsAsUtf16; - private static readonly ReadOnlyMemory s_allScalarsAsUtf8; - - static Utf8Tests() - { - List allScalarsAsUtf16 = new List(); - List allScalarsAsUtf8 = new List(); - - 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 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) - }; - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs similarity index 99% rename from src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.netcoreapp.cs rename to src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs index 3f1517f..5289f03 100644 --- a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.netcoreapp.cs +++ b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs @@ -10,7 +10,7 @@ using Xunit; namespace System.Text.Unicode.Tests { - public partial class Utf8UtilityTests + public class Utf8UtilityTests { private unsafe delegate byte* GetPointerToFirstInvalidByteDel(byte* pInputBuffer, int inputLength, out int utf16CodeUnitCountAdjustment, out int scalarCountAdjustment); private static readonly Lazy _getPointerToFirstInvalidByteFn = CreateGetPointerToFirstInvalidByteFn(); diff --git a/src/libraries/System.Runtime/tests/System/TimeSpanTests.cs b/src/libraries/System.Runtime/tests/System/TimeSpanTests.cs index b559667..965e5ae 100644 --- a/src/libraries/System.Runtime/tests/System/TimeSpanTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeSpanTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace System.Tests { - public partial class TimeSpanTests + public class TimeSpanTests { [Fact] public static void MaxValue() @@ -1070,5 +1070,320 @@ namespace System.Tests { Assert.Equal(expected, Math.Sign(timeSpan1.CompareTo(obj))); } + + public static IEnumerable 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 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(() => TimeSpan.MaxValue * 1.000000001); + Assert.Throws(() => -1.000000001 * TimeSpan.MaxValue); + } + + [Fact] + public static void NaNMultiplication() + { + AssertExtensions.Throws("factor", () => TimeSpan.FromDays(1) * double.NaN); + AssertExtensions.Throws("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(() => TimeSpan.FromDays(1) / 0); + Assert.Throws(() => TimeSpan.FromDays(-1) / 0); + Assert.Throws(() => 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("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(() => TimeSpan.MaxValue.Multiply(1.000000001)); + } + + [Fact] + public static void NamedNaNMultiplication() + { + AssertExtensions.Throws("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(() => TimeSpan.FromDays(1).Divide(0)); + Assert.Throws(() => TimeSpan.FromDays(-1).Divide(0)); + Assert.Throws(() => 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("divisor", () => TimeSpan.FromDays(1).Divide(double.NaN)); + } + + public static IEnumerable 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 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 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("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(() => 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("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles)); + AssertExtensions.Throws("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), new string[] { "s" }, new CultureInfo("en-US"), styles)); + AssertExtensions.Throws("styles", () => TimeSpan.TryParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles, out result)); + AssertExtensions.Throws("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 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(() => 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); + } } } diff --git a/src/libraries/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs deleted file mode 100644 index 13b7969..0000000 --- a/src/libraries/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs +++ /dev/null @@ -1,328 +0,0 @@ -// 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 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 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(() => TimeSpan.MaxValue * 1.000000001); - Assert.Throws(() => -1.000000001 * TimeSpan.MaxValue); - } - - [Fact] - public static void NaNMultiplication() - { - AssertExtensions.Throws("factor", () => TimeSpan.FromDays(1) * double.NaN); - AssertExtensions.Throws("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(() => TimeSpan.FromDays(1) / 0); - Assert.Throws(() => TimeSpan.FromDays(-1) / 0); - Assert.Throws(() => 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("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(() => TimeSpan.MaxValue.Multiply(1.000000001)); - } - - [Fact] - public static void NamedNaNMultiplication() - { - AssertExtensions.Throws("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(() => TimeSpan.FromDays(1).Divide(0)); - Assert.Throws(() => TimeSpan.FromDays(-1).Divide(0)); - Assert.Throws(() => 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("divisor", () => TimeSpan.FromDays(1).Divide(double.NaN)); - } - - public static IEnumerable 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 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 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("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(() => 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("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles)); - AssertExtensions.Throws("styles", () => TimeSpan.ParseExact(inputString.AsSpan(), new string[] { "s" }, new CultureInfo("en-US"), styles)); - AssertExtensions.Throws("styles", () => TimeSpan.TryParseExact(inputString.AsSpan(), "s", new CultureInfo("en-US"), styles, out result)); - AssertExtensions.Throws("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 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(() => 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); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Type/TypePropertyTests.cs b/src/libraries/System.Runtime/tests/System/Type/TypePropertyTests.cs index 01fb958..480ebb1 100644 --- a/src/libraries/System.Runtime/tests/System/Type/TypePropertyTests.cs +++ b/src/libraries/System.Runtime/tests/System/Type/TypePropertyTests.cs @@ -7,7 +7,7 @@ using Xunit; namespace System.Tests.Types { - public abstract partial class TypePropertyTestBase + public abstract class TypePropertyTestBase { public abstract Type CreateType(); @@ -311,6 +311,42 @@ namespace System.Tests.Types { 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 diff --git a/src/libraries/System.Runtime/tests/System/Type/TypePropertyTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Type/TypePropertyTests.netcoreapp.cs deleted file mode 100644 index 169b2ad..0000000 --- a/src/libraries/System.Runtime/tests/System/Type/TypePropertyTests.netcoreapp.cs +++ /dev/null @@ -1,48 +0,0 @@ -// 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); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs b/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs index f14da21..d95c9b9 100644 --- a/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs +++ b/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs @@ -5,7 +5,9 @@ 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; @@ -37,6 +39,27 @@ namespace System.Tests { public partial class TypeTests { + private static readonly IList NonArrayBaseTypes; + + static TypeTests() + { + NonArrayBaseTypes = new List() + { + typeof(int), + typeof(void), + typeof(int*), + typeof(Outside), + typeof(Outside), + typeof(Outside<>).GetTypeInfo().GenericTypeParameters[0], + new object().GetType().GetType() + }; + + if (PlatformDetection.IsWindows) + { + NonArrayBaseTypes.Add(Type.GetTypeFromCLSID(default(Guid))); + } + } + [Fact] public void FilterName_Get_ReturnsExpected() { @@ -285,6 +308,262 @@ namespace System.Tests Assert.Throws(() => Type.ReflectionOnlyGetType("", true, true)); Assert.Throws(() => 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 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 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) }; + yield return new object[] { typeof(Outside.Inside) }; + + 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 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), true }; + yield return new object[] { typeof(Span).MakeByRefType(), false }; + yield return new object[] { typeof(Span).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); + } + + public Span 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 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), 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() { } } public class TypeTestsExtended { @@ -478,3 +757,5 @@ namespace System.Tests public interface GenericInterface { } public interface GenericInterface { } } + +internal class DummyGenericClassForTypeTests { } diff --git a/src/libraries/System.Runtime/tests/System/Type/TypeTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/Type/TypeTests.netcoreapp.cs deleted file mode 100644 index 85d0943..0000000 --- a/src/libraries/System.Runtime/tests/System/Type/TypeTests.netcoreapp.cs +++ /dev/null @@ -1,294 +0,0 @@ -// 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 NonArrayBaseTypes; - - static TypeTestsNetcore() - { - NonArrayBaseTypes = new List() - { - typeof(int), - typeof(void), - typeof(int*), - typeof(Outside), - typeof(Outside), - 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 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 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) }; - yield return new object[] { typeof(Outside.Inside) }; - - 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 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), true }; - yield return new object[] { typeof(Span).MakeByRefType(), false }; - yield return new object[] { typeof(Span).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); - } - - public Span 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 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), 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() { } - } -} - -internal class DummyGenericClassForTypeTestsNetcore { } diff --git a/src/libraries/System.Runtime/tests/System/UInt16Tests.cs b/src/libraries/System.Runtime/tests/System/UInt16Tests.cs index ef837a5..ccc9f47 100644 --- a/src/libraries/System.Runtime/tests/System/UInt16Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt16Tests.cs @@ -8,7 +8,7 @@ using Xunit; namespace System.Tests { - public partial class UInt16Tests + public class UInt16Tests { [Fact] public static void Ctor_Empty() @@ -290,5 +290,105 @@ namespace System.Tests AssertExtensions.Throws(paramName, () => ushort.Parse("1", style)); AssertExtensions.Throws(paramName, () => ushort.Parse("1", style, null)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs deleted file mode 100644 index a6e8301..0000000 --- a/src/libraries/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs +++ /dev/null @@ -1,113 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/UInt32Tests.cs b/src/libraries/System.Runtime/tests/System/UInt32Tests.cs index 9265c13..a31df0e 100644 --- a/src/libraries/System.Runtime/tests/System/UInt32Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt32Tests.cs @@ -9,7 +9,7 @@ using Xunit; namespace System.Tests { - public partial class UInt32Tests + public class UInt32Tests { [Fact] public static void Ctor_Empty() @@ -308,5 +308,105 @@ namespace System.Tests AssertExtensions.Throws(paramName, () => uint.Parse("1", style)); AssertExtensions.Throws(paramName, () => uint.Parse("1", style, null)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs deleted file mode 100644 index 1225062..0000000 --- a/src/libraries/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs +++ /dev/null @@ -1,113 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs index 5976972..3c8b0c5 100644 --- a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs @@ -9,7 +9,7 @@ using Xunit; namespace System.Tests { - public partial class UInt64Tests + public class UInt64Tests { [Fact] public static void Ctor_Empty() @@ -319,5 +319,104 @@ namespace System.Tests AssertExtensions.Throws(paramName, () => ulong.Parse("1", style)); AssertExtensions.Throws(paramName, () => ulong.Parse("1", style, null)); } + + public static IEnumerable 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)); + } + } } } diff --git a/src/libraries/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs deleted file mode 100644 index d10e757..0000000 --- a/src/libraries/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs +++ /dev/null @@ -1,112 +0,0 @@ -// 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 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)); - } - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs index f4c922e..53cd55b 100644 --- a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs @@ -8,7 +8,7 @@ using Xunit; namespace System.Tests { - public static partial class UIntPtrTests + public static class UIntPtrTests { private static unsafe bool Is64Bit => sizeof(void*) == 8; @@ -113,6 +113,9 @@ namespace System.Tests Assert.Equal(expected, ptr1 == ptr2); Assert.Equal(!expected, ptr1 != ptr2); Assert.Equal(expected, ptr1.GetHashCode().Equals(ptr2.GetHashCode())); + + IEquatable iEquatable = ptr1; + Assert.Equal(expected, iEquatable.Equals((UIntPtr)obj)); } Assert.Equal(expected, ptr1.Equals(obj)); Assert.Equal(ptr1.GetHashCode(), ptr1.GetHashCode()); diff --git a/src/libraries/System.Runtime/tests/System/UIntPtrTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/UIntPtrTests.netcoreapp.cs deleted file mode 100644 index d55a968..0000000 --- a/src/libraries/System.Runtime/tests/System/UIntPtrTests.netcoreapp.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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 iEquatable = ptr; - Assert.Equal(expected, iEquatable.Equals((UIntPtr)obj)); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/VersionTests.cs b/src/libraries/System.Runtime/tests/System/VersionTests.cs index 423652f..b9f3a4a 100644 --- a/src/libraries/System.Runtime/tests/System/VersionTests.cs +++ b/src/libraries/System.Runtime/tests/System/VersionTests.cs @@ -7,7 +7,7 @@ using Xunit; namespace System.Tests { - public partial class VersionTests + public class VersionTests { [Fact] public void Ctor_Default() @@ -322,5 +322,89 @@ namespace System.Tests Assert.Equal(version.Build, clone.Build); Assert.Equal(version.Revision, clone.Revision); } + + public static IEnumerable 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("fieldCount", () => version.TryFormat(dest, -1, out charsWritten)); // Index < 0 + AssertExtensions.Throws("fieldCount", () => version.TryFormat(dest, maxFieldCount + 1, out charsWritten)); // Index > version.fieldCount + } } } diff --git a/src/libraries/System.Runtime/tests/System/VersionTests.netcoreapp.cs b/src/libraries/System.Runtime/tests/System/VersionTests.netcoreapp.cs deleted file mode 100644 index f33a046..0000000 --- a/src/libraries/System.Runtime/tests/System/VersionTests.netcoreapp.cs +++ /dev/null @@ -1,96 +0,0 @@ -// 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 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("fieldCount", () => version.TryFormat(dest, -1, out charsWritten)); // Index < 0 - AssertExtensions.Throws("fieldCount", () => version.TryFormat(dest, maxFieldCount + 1, out charsWritten)); // Index > version.fieldCount - } - } -}