Enhance existing Marshal tests (dotnet/corefx#31196)
authorHugh Bellamy <hughbellars@gmail.com>
Thu, 30 Aug 2018 21:11:41 +0000 (22:11 +0100)
committerLuqun Lou <luqunl@users.noreply.github.com>
Thu, 30 Aug 2018 21:11:41 +0000 (14:11 -0700)
Commit migrated from https://github.com/dotnet/corefx/commit/f024dd1d54aa29354e8840c5ead72f4fbd8cf1de

17 files changed:
src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/ClassInterfaceAttributeTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/ChangeWrapperHandleStrengthTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/Common/Variant.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/DestroyStructureTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GenerateGuidForTypeTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GenerateProgIdForTypeTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetIDispatchForObjectTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetNativeVariantForObjectTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetTypedObjectForIUnknownTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/IsComObjectTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/OffsetOfTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/PrelinkTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/PtrToStructureTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/SizeOfTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/StructureToPtrTests.cs
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/UnsafeAddrOfPinnedArrayElementTests.cs

index 458a20a..f0e0461 100644 (file)
     <Compile Include="System\Runtime\InteropServices\Marshal\ZeroFreeGlobalAllocUnicodeTests.cs" />
     <Compile Include="System\Runtime\InteropServices\Marshal\Common\CommonTypes.cs" />
     <Compile Include="System\Runtime\InteropServices\Marshal\Common\CommonTypes.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
+    <Compile Include="System\Runtime\InteropServices\Marshal\Common\Variant.cs" />
     <Compile Include="System\Runtime\InteropServices\Marshal\ReadWrite\ByteTests.cs" />
     <Compile Include="System\Runtime\InteropServices\Marshal\ReadWrite\Int16Tests.cs" />
     <Compile Include="System\Runtime\InteropServices\Marshal\ReadWrite\Int32Tests.cs" />
index 220bb00..f004b71 100644 (file)
@@ -12,10 +12,10 @@ namespace System.Runtime.InteropServices.Tests
         [InlineData(-1)]
         [InlineData(0)]
         [InlineData(4)]
-        public void Ctor_ShortClassInterfaceType(ClassInterfaceType classInterfaceType)
+        public void Ctor_ShortClassInterfaceType(short classInterfaceType)
         {
             var attribute = new ClassInterfaceAttribute(classInterfaceType);
-            Assert.Equal(classInterfaceType, attribute.Value);
+            Assert.Equal((ClassInterfaceType)classInterfaceType, attribute.Value);
         }
 
         [Theory]
index cd03138..a7c2382 100644 (file)
@@ -2,12 +2,47 @@
 // 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 System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
 {
-    public class ChangeWrapperHandleStrengthTests
+    public partial class ChangeWrapperHandleStrengthTests
     {
+        public static IEnumerable<object[]> ChangeWrapperHandleStrength_TestData()
+        {
+            yield return new object[] { new object() };
+            yield return new object[] { 10 };
+            yield return new object[] { "string" };
+
+            yield return new object[] { new NonGenericClass() };
+            yield return new object[] { new GenericClass<string>() };
+            yield return new object[] { new Dictionary<string, int>() };
+            yield return new object[] { new NonGenericStruct() };
+            yield return new object[] { new GenericStruct<string>() };
+            yield return new object[] { Int32Enum.Value1 };
+
+            yield return new object[] { new int[] { 10 } };
+            yield return new object[] { new int[][] { new int[] { 10 } } };
+            yield return new object[] { new int[,] { { 10 } } };
+
+            MethodInfo method = typeof(ChangeWrapperHandleStrengthTests).GetMethod(nameof(NonGenericMethod));
+            Delegate d = method.CreateDelegate(typeof(NonGenericDelegate));
+            yield return new object[] { d };
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetNative))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        [MemberData(nameof(ChangeWrapperHandleStrength_TestData))]
+        public void ChangeWrapperHandleStrength_ValidObject_Success(object otp)
+        {
+            Marshal.ChangeWrapperHandleStrength(otp, fIsWeak: true);
+            Marshal.ChangeWrapperHandleStrength(otp, fIsWeak: false);
+        }
+
         [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetNative))]
         [PlatformSpecific(TestPlatforms.Windows)]
         public void ChangeWrapperHandleStrength_NullObject_ThrowsArgumentNullException()
@@ -16,6 +51,19 @@ namespace System.Runtime.InteropServices.Tests
             AssertExtensions.Throws<ArgumentNullException>("otp", () => Marshal.ChangeWrapperHandleStrength(null, fIsWeak: false));
         }
 
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetNative))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public void ChangeWrapperHandleStrength_ObjectNotCollectible_ThrowsNotSupportedException()
+        {
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            Type type = typeBuilder.CreateType();
+
+            object o = Activator.CreateInstance(type);
+            Assert.Throws<NotSupportedException>(() => Marshal.ChangeWrapperHandleStrength(o, fIsWeak: true));
+        }
+
         [Fact]
         [PlatformSpecific(TestPlatforms.AnyUnix)]
         public void ChangeWrapperHandleStrength_Unix_ThrowsPlatformNotSupportedException()
@@ -23,5 +71,10 @@ namespace System.Runtime.InteropServices.Tests
             Assert.Throws<PlatformNotSupportedException>(() => Marshal.ChangeWrapperHandleStrength(null, fIsWeak: true));
             Assert.Throws<PlatformNotSupportedException>(() => Marshal.ChangeWrapperHandleStrength(null, fIsWeak: false));
         }
+
+        public static void NonGenericMethod(int i) { }
+        public delegate void NonGenericDelegate(int i);
+
+        public enum Int32Enum : int { Value1, Value2 }
     }
 }
diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/Common/Variant.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/Common/Variant.cs
new file mode 100644 (file)
index 0000000..087e567
--- /dev/null
@@ -0,0 +1,18 @@
+// 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.
+
+namespace System.Runtime.InteropServices.Tests.Common
+{
+    public struct Variant
+    {
+#pragma warning disable 0649
+        public ushort vt;
+        public ushort wReserved1;
+        public ushort wReserved2;
+        public ushort wReserved3;
+        public IntPtr bstrVal;
+        public IntPtr pRecInfo;
+#pragma warning restore 0649
+    }
+}
index 9a4c7d9..f547d54 100644 (file)
 // 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 System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
 {
     public class DestroyStructureTests
     {
-        [StructLayout(LayoutKind.Sequential)]
-        public struct SomeTestStruct
+        [Fact]
+        public void DestroyStructure_Generic_Success()
         {
-            public int i;
-            public String s;
+            var structure = new TestStruct();
+            IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(structure));
+            try
+            {
+                structure.s = null;
+
+                Marshal.StructureToPtr(structure, ptr, fDeleteOld: false);
+                Marshal.DestroyStructure<TestStruct>(ptr);
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(ptr);
+            }
         }
 
-        [StructLayout(LayoutKind.Auto)]
-        public struct SomeTestStruct_Auto
+        [Fact]
+        public void DestroyStructure_NonGeneric_Succes()
         {
-            public int i;
+            var structure = new TestStruct();
+            IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(structure));
+            try
+            {
+                structure.s = null;
+
+                Marshal.StructureToPtr(structure, ptr, fDeleteOld: false);
+                Marshal.DestroyStructure(ptr, typeof(TestStruct));
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(ptr);
+            }
+        }
+
+        [Fact]
+        public void DestroyStructure_Blittable_Success()
+        {
+            Marshal.DestroyStructure<int>((IntPtr)1);
+            Marshal.DestroyStructure((IntPtr)1, typeof(int));
+        }
+
+        [Fact]
+        public void DestroyStructure_ZeroPointer_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.DestroyStructure<TestStruct>(IntPtr.Zero));
+            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.DestroyStructure(IntPtr.Zero, typeof(TestStruct)));
         }
 
         [Fact]
-        public void DestroyStructure_Negative()
+        public void DestroyStructure_NullStructureType_ThrowsArgumentNullException()
         {
-            IntPtr ip;
+            AssertExtensions.Throws<ArgumentNullException>("structureType", () => Marshal.DestroyStructure((IntPtr)1, null));
+        }
+        
+        public static IEnumerable<object[]> DestroyStructure_InvalidType_TestData()
+        {
+            yield return new object[] { typeof(int).MakeByRefType() };
+            yield return new object[] { typeof(string) };
+
+            yield return new object[] { typeof(NonGenericClass) };
+            yield return new object[] { typeof(GenericClass<>) };
+            yield return new object[] { typeof(GenericClass<string>) };
+            yield return new object[] { typeof(AbstractClass) };
 
-            ip = IntPtr.Zero;
-            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.DestroyStructure<SomeTestStruct>(ip));
+            yield return new object[] { typeof(GenericStruct<>) };
+            yield return new object[] { typeof(GenericStruct<string>) };
+            yield return new object[] { typeof(GenericInterface<>) };
+            yield return new object[] { typeof(GenericInterface<string>) };
 
-            ip = new IntPtr(123);
-            AssertExtensions.Throws<ArgumentNullException>("structureType", () => Marshal.DestroyStructure(ip, null));
+            yield return new object[] { typeof(GenericClass<>).GetTypeInfo().GenericTypeParameters[0] };
 
-            SomeTestStruct_Auto someTs_Auto = new SomeTestStruct_Auto();
-            Assert.Throws<ArgumentException>(() => Marshal.DestroyStructure(ip, someTs_Auto.GetType()));
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.Run);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            yield return new object[] { typeBuilder };
+        }
+
+        [Theory]
+        [MemberData(nameof(DestroyStructure_InvalidType_TestData))]
+        public void DestroyStructure_NonRuntimeType_ThrowsArgumentException(Type invalidType)
+        {
+            AssertExtensions.Throws<ArgumentException>("structureType", () => Marshal.DestroyStructure((IntPtr)1, invalidType));
         }
 
         [Fact]
-        public void DestroyStructure_Positive()
+        public void DestroyStructure_AutoLayout_ThrowsArgumentException()
         {
-            SomeTestStruct someTestStruct = new SomeTestStruct();
-            IntPtr ip = Marshal.AllocHGlobal(Marshal.SizeOf(someTestStruct));
-            try
-            {
-                someTestStruct.s = null;
-                //Generic
-                Marshal.StructureToPtr(someTestStruct, ip, false);
-                Marshal.DestroyStructure<SomeTestStruct>(ip);
-                //None-Generic
-                Marshal.StructureToPtr(someTestStruct, ip, false);
-                Marshal.DestroyStructure(ip, typeof(SomeTestStruct));
-            }
-            finally
-            {
-                Marshal.FreeHGlobal(ip);
-            }
+            AssertExtensions.Throws<ArgumentException>("structureType", () => Marshal.DestroyStructure<AutoLayoutStruct>((IntPtr)1));
+            AssertExtensions.Throws<ArgumentException>("structureType", () => Marshal.DestroyStructure((IntPtr)1, typeof(AutoLayoutStruct)));
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct TestStruct
+        {
+            public int i;
+            public string s;
+        }
+
+        [StructLayout(LayoutKind.Auto)]
+        public struct AutoLayoutStruct
+        {
+            public int i;
         }
     }
 }
index 2a7b823..49d39b9 100644 (file)
@@ -42,6 +42,12 @@ namespace System.Runtime.InteropServices.Tests
             }
 
             yield return new object[] { typeof(ClassWithGuidAttribute) };
+
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            Type collectibleType = typeBuilder.CreateType();
+            yield return new object[] { collectibleType };
         }
 
         [Theory]
index 90c4df9..e5048f7 100644 (file)
@@ -60,6 +60,12 @@ namespace System.Runtime.InteropServices.Tests
 
             yield return new object[] { typeof(GenericClass<>) };
             yield return new object[] { typeof(GenericClass<>).GetTypeInfo().GenericTypeParameters[0] };
+
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            Type collectibleType = typeBuilder.CreateType();
+            yield return new object[] { collectibleType };
         }
 
         [Theory]
index 2557215..93cc3b1 100644 (file)
@@ -3,36 +3,34 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.Emit;
 using System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
 {
-    public class GetIDispatchForObjectTests
+    public partial class GetIDispatchForObjectTests
     {
         public static IEnumerable<object[]> GetIDispatchForObject_Valid_TestData()
         {
             yield return new object[] { new NonGenericClass() };
             yield return new object[] { new NonGenericStruct() };
-
-            Type type = Type.GetTypeFromCLSID(new Guid("927971f5-0939-11d1-8be1-00c04fd8d503"));
-            object comObject = Activator.CreateInstance(type);
-            yield return new object[] { comObject };
         }
 
         [Theory]
         [MemberData(nameof(GetIDispatchForObject_Valid_TestData))]
         [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework, "Marshal.GetIDispatchForObject is not implemented in .NET Core.")]
-        public void GetIDispatchForObject_NetFramework_ReturnsNonZero(object o)
+        public void GetIDispatchForObject_ValidObject_Roundtrips(object o)
         {
-            IntPtr iDispatch = Marshal.GetIDispatchForObject(o);
+            IntPtr ptr = Marshal.GetIDispatchForObject(o);
             try
             {
-                Assert.NotEqual(IntPtr.Zero, iDispatch);
+                Assert.NotEqual(IntPtr.Zero, ptr);
             }
             finally
             {
-                Marshal.Release(iDispatch);
+                Marshal.Release(ptr);
             }
         }
 
@@ -49,19 +47,33 @@ namespace System.Runtime.InteropServices.Tests
             yield return new object[] { new GenericStruct<string>() };
         }
 
-        [Theory]
-        [MemberData(nameof(GetIDispatchForObject_Invalid_TestData))]
+        [Fact]
         [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework, "Marshal.GetIDispatchForObject is not implemented in .NET Core.")]
-        public void GetIDispatchForObject_InvalidObject_ThrowsInvalidCastException(object o)
+        public void GetIDispatchForObject_NullObject_ThrowsArgumentNullException()
         {
-            Assert.Throws<InvalidCastException>(() => Marshal.GetIDispatchForObject(o));
+            AssertExtensions.Throws<ArgumentNullException>("o", () => Marshal.GetIDispatchForObject(null));
         }
 
-        [Fact]
+        [ConditionalFact]
+        [PlatformSpecific(TestPlatforms.Windows)]
         [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework, "Marshal.GetIDispatchForObject is not implemented in .NET Core.")]
-        public void GetIDispatchForObject_NullObject_ThrowsArgumentNullException()
+        public void GetIDispatchForObject_ObjectNotCollectible_ThrowsNotSupportedException()
         {
-            AssertExtensions.Throws<ArgumentNullException>("o", () => Marshal.GetIDispatchForObject(null));
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            Type type = typeBuilder.CreateType();
+
+            object o = Activator.CreateInstance(type);
+            Assert.Throws<NotSupportedException>(() => Marshal.GetIDispatchForObject(o));
+        }
+
+        [Theory]
+        [MemberData(nameof(GetIDispatchForObject_Invalid_TestData))]
+        [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework, "Marshal.GetIDispatchForObject is not implemented in .NET Core.")]
+        public void GetIDispatchForObject_InvalidObject_ThrowsInvalidCastException(object o)
+        {
+            Assert.Throws<InvalidCastException>(() => Marshal.GetIDispatchForObject(o));
         }
     }
 }
index 0628551..5208c04 100644 (file)
 // 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.Drawing;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
+#pragma warning disable 618
+
 namespace System.Runtime.InteropServices.Tests
 {
     [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "GetNativeVariantForObject() not supported on UWP")]
-    public class GetNativeVariantForObjectTests
+    public partial class GetNativeVariantForObjectTests
     {
-        internal struct Variant
+        public static IEnumerable<object[]> GetNativeVariantForObject_RoundtrippingPrimitives_TestData()
         {
-#pragma warning disable 0649
-            public ushort vt;
-            public ushort wReserved1;
-            public ushort wReserved2;
-            public ushort wReserved3;
-            public IntPtr bstrVal;
-            public IntPtr pRecInfo;
-#pragma warning restore 0649
+            yield return new object[] { null, VarEnum.VT_EMPTY, IntPtr.Zero };
+
+            yield return new object[] { (sbyte)10, VarEnum.VT_I1, (IntPtr)10 };
+            yield return new object[] { (short)10, VarEnum.VT_I2, (IntPtr)10 };
+            yield return new object[] { 10, VarEnum.VT_I4, (IntPtr)10 };
+            yield return new object[] { (long)10, VarEnum.VT_I8, (IntPtr)10 };
+            yield return new object[] { (byte)10, VarEnum.VT_UI1, (IntPtr)10 };
+            yield return new object[] { (ushort)10, VarEnum.VT_UI2, (IntPtr)10 };
+            yield return new object[] { (uint)10, VarEnum.VT_UI4, (IntPtr)10 };
+            yield return new object[] { (ulong)10, VarEnum.VT_UI8, (IntPtr)10 };
+
+            yield return new object[] { true, VarEnum.VT_BOOL, (IntPtr)ushort.MaxValue };
+            yield return new object[] { false, VarEnum.VT_BOOL, IntPtr.Zero };
+
+            yield return new object[] { 10m, VarEnum.VT_DECIMAL, (IntPtr)10 };
+
+            // Well known types.
+            DateTime dateTime = new DateTime(1899, 12, 30).AddDays(20);
+            yield return new object[] { dateTime, VarEnum.VT_DATE, (IntPtr)(-1) };
+
+            yield return new object[] { DBNull.Value, VarEnum.VT_NULL, IntPtr.Zero };
+            yield return new object[] { DBNull.Value, VarEnum.VT_NULL, IntPtr.Zero };
+
+            // Arrays.
+            yield return new object[] { new sbyte[] { 10, 11, 12 }, (VarEnum)8208, (IntPtr)(-1) };
+            yield return new object[] { new short[] { 10, 11, 12 }, (VarEnum)8194, (IntPtr)(-1) };
+            yield return new object[] { new int[] { 10, 11, 12 }, (VarEnum)8195, (IntPtr)(-1) };
+            yield return new object[] { new long[] { 10, 11, 12 }, (VarEnum)8212, (IntPtr)(-1) };
+            yield return new object[] { new byte[] { 10, 11, 12 }, (VarEnum)8209, (IntPtr)(-1) };
+            yield return new object[] { new ushort[] { 10, 11, 12 }, (VarEnum)8210, (IntPtr)(-1) };
+            yield return new object[] { new uint[] { 10, 11, 12 }, (VarEnum)8211, (IntPtr)(-1) };
+            yield return new object[] { new ulong[] { 10, 11, 12 }, (VarEnum)8213, (IntPtr)(-1) };
+
+            yield return new object[] { new bool[] { true, false }, (VarEnum)8203, (IntPtr)(-1) };
+
+            yield return new object[] { new float[] { 10, 11, 12 }, (VarEnum)8196, (IntPtr)(-1) };
+            yield return new object[] { new double[] { 10, 11, 12 }, (VarEnum)8197, (IntPtr)(-1) };
+            yield return new object[] { new decimal[] { 10m, 11m, 12m }, (VarEnum)8206, (IntPtr)(-1) };
+
+            yield return new object[] { new object[] { 10, 11, 12 }, (VarEnum)8204, (IntPtr)(-1) };
+            yield return new object[] { new string[] { "a", "b", "c" }, (VarEnum)8200, (IntPtr)(-1) };
+
+            yield return new object[] { new TimeSpan[] { new TimeSpan(10) }, (VarEnum)8228, (IntPtr)(-1) };
+            yield return new object[] { new int[,] { { 10 }, { 11 }, { 12 } }, (VarEnum)8195, (IntPtr)(-1) };
+
+            // Objects.
+            var nonGenericClass = new NonGenericClass();
+            yield return new object[] { nonGenericClass, VarEnum.VT_DISPATCH, (IntPtr)(-1) };
+
+            var valueType = new StructWithValue { Value = 10 };
+            yield return new object[] { valueType, VarEnum.VT_RECORD, (IntPtr)(-1) };
+
+            var genericClass = new GenericClass<string>();
+            yield return new object[] { new object[] { nonGenericClass, genericClass, null }, (VarEnum)8204, (IntPtr)(-1) };
+
+            yield return new object[] { new object[] { valueType, null }, (VarEnum)8204, (IntPtr)(-1) };
+
+            // Delegate.
+            MethodInfo method = typeof(GetNativeVariantForObjectTests).GetMethod(nameof(NonGenericMethod));
+            Delegate d = method.CreateDelegate(typeof(NonGenericDelegate));
+            yield return new object[] { d, VarEnum.VT_DISPATCH, (IntPtr)(-1) };
         }
 
-#pragma warning disable 618
+        [Theory]
+        [MemberData(nameof(GetNativeVariantForObject_RoundtrippingPrimitives_TestData))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        [ActiveIssue(31077, ~TargetFrameworkMonikers.NetFramework)]
+        public void GetNativeVariantForObject_RoundtrippingPrimitives_Success(object primitive, VarEnum expectedVarType, IntPtr expectedValue)
+        {
+            GetNativeVariantForObject_ValidObject_Success(primitive, expectedVarType, expectedValue, primitive);
+        }
 
         [Fact]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public static void EmptyObject()
+        public void GetNativeVariantForObject_TypeMissing_Success()
+        {
+            // This cannot be in the test data as XUnit uses MethodInfo.Invoke to call test methods and
+            // Type.Missing is handled specially for parameters with default values.
+            GetNativeVariantForObject_RoundtrippingPrimitives_Success(Type.Missing, VarEnum.VT_ERROR, (IntPtr)(-1));
+        }
+
+        public static IEnumerable<object[]> GetNativeVariantForObject_NonRoundtrippingPrimitives_TestData()
         {
-            Variant v = new Variant();
+            // GetNativeVariantForObject supports char, but internally recognizes it the same as ushort
+            // because the native variant type uses mscorlib type VarEnum to store what type it contains.
+            // To get back the original char, use GetObjectForNativeVariant<ushort> and cast to char.
+            yield return new object[] { 'a', VarEnum.VT_UI2, (IntPtr)'a', (ushort)97 };
+            yield return new object[] { new char[] { 'a', 'b', 'c' }, (VarEnum)8210, (IntPtr)(-1), new ushort[] { 'a', 'b', 'c' } };
+
+            // IntPtr/UIntPtr objects are converted to int/uint respectively.
+            yield return new object[] { (IntPtr)10, VarEnum.VT_INT, (IntPtr)10, 10 };
+            yield return new object[] { (UIntPtr)10, VarEnum.VT_UINT, (IntPtr)10, (uint)10 };
+
+            yield return new object[] { new IntPtr[] { (IntPtr)10, (IntPtr)11, (IntPtr)12 }, (VarEnum)8212, (IntPtr)(-1), new long[] { 10, 11, 12 } };
+            yield return new object[] { new UIntPtr[] { (UIntPtr)10, (UIntPtr)11, (UIntPtr)12 }, (VarEnum)8213, (IntPtr)(-1), new ulong[] { 10, 11, 12 } };
+
+            // DateTime is converted to VT_DATE which is offset from December 30, 1899.
+            DateTime earlyDateTime = new DateTime(1899, 12, 30);
+            yield return new object[] { earlyDateTime, VarEnum.VT_DATE, IntPtr.Zero, new DateTime(1899, 12, 30) };
+
+            // Wrappers.
+            yield return new object[] { new UnknownWrapper(10), VarEnum.VT_UNKNOWN, IntPtr.Zero, null };
+            if (!PlatformDetection.IsNetCore)
+            {
+                yield return new object[] { new DispatchWrapper(10), VarEnum.VT_DISPATCH, IntPtr.Zero, null };
+            }
+            else
+            {
+                Assert.Throws<PlatformNotSupportedException>(() => new DispatchWrapper(10));
+            }
+            yield return new object[] { new ErrorWrapper(10), VarEnum.VT_ERROR, (IntPtr)10, 10 };
+            yield return new object[] { new CurrencyWrapper(10), VarEnum.VT_CY, (IntPtr)100000, 10m };
+            yield return new object[] { new BStrWrapper("a"), VarEnum.VT_BSTR, (IntPtr)(-1), "a" };
+            yield return new object[] { new BStrWrapper(null), VarEnum.VT_BSTR, IntPtr.Zero, null };
+
+            yield return new object[] { new UnknownWrapper[] { new UnknownWrapper(null), new UnknownWrapper(10) }, (VarEnum)8205, (IntPtr)(-1), new object[] { null, 10 }  };
+            if (!PlatformDetection.IsNetCore)
+            {
+                yield return new object[] { new DispatchWrapper[] { new DispatchWrapper(null), new DispatchWrapper(10) }, (VarEnum)8201, (IntPtr)(-1), new object[] { null, 10 } };
+            }
+            else
+            {
+                Assert.Throws<PlatformNotSupportedException>(() => new DispatchWrapper(10));
+            }
+            yield return new object[] { new ErrorWrapper[] { new ErrorWrapper(10) }, (VarEnum)8202, (IntPtr)(-1), new uint[] { 10 } };
+            yield return new object[] { new CurrencyWrapper[] { new CurrencyWrapper(10) }, (VarEnum)8198, (IntPtr)(-1), new decimal[] { 10 } };
+            yield return new object[] { new BStrWrapper[] { new BStrWrapper("a"), new BStrWrapper(null), new BStrWrapper("c") }, (VarEnum)8200, (IntPtr)(-1), new string[] { "a", null, "c" } };
+
+            // Objects.
+            var nonGenericClass = new NonGenericClass();
+            yield return new object[] { new NonGenericClass[] { nonGenericClass, null }, (VarEnum)8201, (IntPtr)(-1), new object[] { nonGenericClass, null } };
+
+            var genericClass = new GenericClass<string>();
+            yield return new object[] { new GenericClass<string>[] { genericClass, null }, (VarEnum)8205, (IntPtr)(-1), new object[] { genericClass, null } };
+
+            var nonGenericStruct = new NonGenericStruct();
+            yield return new object[] { new NonGenericStruct[] { nonGenericStruct }, (VarEnum)8228, (IntPtr)(-1), new NonGenericStruct[] { nonGenericStruct } };
+
+            var classWithInterface = new ClassWithInterface();
+            var structWithInterface = new StructWithInterface();
+            yield return new object[] { new ClassWithInterface[] { classWithInterface, null }, (VarEnum)8201, (IntPtr)(-1), new object[] { classWithInterface, null } };
+            yield return new object[] { new StructWithInterface[] { structWithInterface }, (VarEnum)8228, (IntPtr)(-1), new StructWithInterface[] { structWithInterface } };
+            yield return new object[] { new NonGenericInterface[] { classWithInterface, structWithInterface, null }, (VarEnum)8201, (IntPtr)(-1), new object[] { classWithInterface, structWithInterface, null } };
+
+            // Enums.
+            yield return new object[] { SByteEnum.Value2, VarEnum.VT_I1, (IntPtr)1, (sbyte)1 };
+            yield return new object[] { Int16Enum.Value2, VarEnum.VT_I2, (IntPtr)1, (short)1 };
+            yield return new object[] { Int32Enum.Value2, VarEnum.VT_I4, (IntPtr)1, 1 };
+            yield return new object[] { Int64Enum.Value2, VarEnum.VT_I8, (IntPtr)1, (long)1 };
+            yield return new object[] { ByteEnum.Value2, VarEnum.VT_UI1, (IntPtr)1, (byte)1 };
+            yield return new object[] { UInt16Enum.Value2, VarEnum.VT_UI2, (IntPtr)1, (ushort)1 };
+            yield return new object[] { UInt32Enum.Value2, VarEnum.VT_UI4, (IntPtr)1, (uint)1 };
+            yield return new object[] { UInt64Enum.Value2, VarEnum.VT_UI8, (IntPtr)1, (ulong)1 };
+
+            yield return new object[] { new SByteEnum[] { SByteEnum.Value2 }, (VarEnum)8208, (IntPtr)(-1), new sbyte[] { 1 } };
+            yield return new object[] { new Int16Enum[] { Int16Enum.Value2 }, (VarEnum)8194, (IntPtr)(-1), new short[] { 1 } };
+            yield return new object[] { new Int32Enum[] { Int32Enum.Value2 }, (VarEnum)8195, (IntPtr)(-1), new int[] { 1 } };
+            yield return new object[] { new Int64Enum[] { Int64Enum.Value2 }, (VarEnum)8212, (IntPtr)(-1), new long[] { 1 } };
+            yield return new object[] { new ByteEnum[] { ByteEnum.Value2 }, (VarEnum)8209, (IntPtr)(-1), new byte[] { 1 } };
+            yield return new object[] { new UInt16Enum[] { UInt16Enum.Value2 }, (VarEnum)8210, (IntPtr)(-1), new ushort[] { 1 } };
+            yield return new object[] { new UInt32Enum[] { UInt32Enum.Value2 }, (VarEnum)8211, (IntPtr)(-1), new uint[] { 1 } };
+            yield return new object[] { new UInt64Enum[] { UInt64Enum.Value2 }, (VarEnum)8213, (IntPtr)(-1), new ulong[] { 1 } };
+
+            // Color is converted to uint.
+            yield return new object[] { Color.FromArgb(10), VarEnum.VT_UI4, (IntPtr)655360, (uint)655360 };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetNativeVariantForObject_NonRoundtrippingPrimitives_TestData))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        [ActiveIssue(31077, ~TargetFrameworkMonikers.NetFramework)]
+        public void GetNativeVariantForObject_ValidObject_Success(object primitive, VarEnum expectedVarType, IntPtr expectedValue, object expectedRoundtripValue)
+        {
+            var v = new Variant();
             IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
             try
             {
-                Marshal.GetNativeVariantForObject(null, pNative);
+                Marshal.GetNativeVariantForObject(primitive, pNative);
+
+                Variant result = Marshal.PtrToStructure<Variant>(pNative);
+                Assert.Equal(expectedVarType, (VarEnum)result.vt);
+                if (expectedValue != (IntPtr)(-1))
+                {
+                    Assert.Equal(expectedValue, result.bstrVal);
+                }
+                else
+                {
+                    Assert.NotEqual((IntPtr)(-1), result.bstrVal);
+                    Assert.NotEqual(IntPtr.Zero, result.bstrVal);
+                }
+
+                // Make sure it roundtrips.
+                Assert.Equal(expectedRoundtripValue, Marshal.GetObjectForNativeVariant(pNative));
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(pNative);
+            }
+        }
+
+        [Theory]
+        [InlineData("")]
+        [InlineData("99")]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public void GetNativeVariantForObject_String_Success(string obj)
+        {
+            var v = new Variant();
+            IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
+            try
+            {
+                Marshal.GetNativeVariantForObject(obj, pNative);
+
+                Variant result = Marshal.PtrToStructure<Variant>(pNative);
+                try
+                {
+                    Assert.Equal(VarEnum.VT_BSTR, (VarEnum)result.vt);
+                    Assert.Equal(obj, Marshal.PtrToStringBSTR(result.bstrVal));
+
+                    object o = Marshal.GetObjectForNativeVariant(pNative);
+                    Assert.Equal(obj, o);
+                }
+                finally
+                {
+                    Marshal.FreeBSTR(result.bstrVal);
+                }
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(pNative);
+            }
+        }
+
+        [Theory]
+        [InlineData(3.14)]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public unsafe void GetNativeVariantForObject_Double_Success(double obj)
+        {
+            var v = new Variant();
+            IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
+            try
+            {
+                Marshal.GetNativeVariantForObject(obj, pNative);
+
+                Variant result = Marshal.PtrToStructure<Variant>(pNative);
+                Assert.Equal(VarEnum.VT_R8, (VarEnum)result.vt);
+                Assert.Equal(*((IntPtr*)&obj), result.bstrVal);
+
                 object o = Marshal.GetObjectForNativeVariant(pNative);
-                Assert.Null(o);
+                Assert.Equal(obj, o);
             }
             finally
             {
@@ -41,17 +274,23 @@ namespace System.Runtime.InteropServices.Tests
             }
         }
 
-        [Fact]
+        [Theory]
+        [InlineData(3.14f)]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public static void PrimitiveType()
+        public unsafe void GetNativeVariantForObject_Float_Success(float obj)
         {
-            Variant v = new Variant();
+            var v = new Variant();
             IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
             try
             {
-                Marshal.GetNativeVariantForObject<ushort>(99, pNative);
-                ushort actual = Marshal.GetObjectForNativeVariant<ushort>(pNative);
-                Assert.Equal(99, actual);
+                Marshal.GetNativeVariantForObject(obj, pNative);
+
+                Variant result = Marshal.PtrToStructure<Variant>(pNative);
+                Assert.Equal(VarEnum.VT_R4, (VarEnum)result.vt);
+                Assert.Equal(*((IntPtr*)&obj), result.bstrVal);
+
+                object o = Marshal.GetObjectForNativeVariant(pNative);
+                Assert.Equal(obj, o);
             }
             finally
             {
@@ -60,20 +299,61 @@ namespace System.Runtime.InteropServices.Tests
         }
 
         [Fact]
+        [PlatformSpecific(TestPlatforms.AnyUnix)]
+        public void GetNativeVariantForObject_Unix_ThrowsPlatformNotSupportedException()
+        {
+            Assert.Throws<PlatformNotSupportedException>(() => Marshal.GetNativeVariantForObject(new object(), IntPtr.Zero));
+            Assert.Throws<PlatformNotSupportedException>(() => Marshal.GetNativeVariantForObject(1, IntPtr.Zero));
+        }
+
+        [Fact]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public static void CharType()
+        public void GetNativeVariantForObject_ZeroPointer_ThrowsArgumentNullException()
         {
-            // GetNativeVariantForObject supports char, but internally recognizes it the same as ushort
-            // because the native variant type uses mscorlib type VarEnum to store what type it contains.
-            // To get back the original char, use GetObjectForNativeVariant<ushort> and cast to char.
-            Variant v = new Variant();
+            AssertExtensions.Throws<ArgumentNullException>("pDstNativeVariant", () => Marshal.GetNativeVariantForObject(new object(), IntPtr.Zero));
+            AssertExtensions.Throws<ArgumentNullException>("pDstNativeVariant", () => Marshal.GetNativeVariantForObject<int>(1, IntPtr.Zero));
+        }
+
+        public static IEnumerable<object[]> GetNativeVariantForObject_GenericObject_TestData()
+        {
+            yield return new object[] { new GenericClass<string>() };
+            yield return new object[] { new GenericStruct<string>() };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetNativeVariantForObject_GenericObject_TestData))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public void GetNativeVariantForObject_GenericObject_ThrowsArgumentException(object obj)
+        {
+            AssertExtensions.Throws<ArgumentException>("obj", () => Marshal.GetNativeVariantForObject(obj, (IntPtr)1));
+            AssertExtensions.Throws<ArgumentException>("obj", () => Marshal.GetNativeVariantForObject<object>(obj, (IntPtr)1));
+        }
+
+        public static IEnumerable<object[]> GetNativeVariant_NotInteropCompatible_TestData()
+        {
+            yield return new object[] { new TimeSpan(10) };
+
+            yield return new object[] { new object[] { new GenericStruct<string>() } };
+
+            yield return new object[] { new GenericStruct<string>[0]};
+            yield return new object[] { new GenericStruct<string>[] { new GenericStruct<string>() } };
+
+            yield return new object[] { new Color[0] };
+            yield return new object[] { new Color[] { Color.FromArgb(10) } };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetNativeVariant_NotInteropCompatible_TestData))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        [ActiveIssue(31077, ~TargetFrameworkMonikers.NetFramework)]
+        public void GetNativeVariant_NotInteropCompatible_ThrowsArgumentException(object obj)
+        {
+            var v = new Variant();
             IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
             try
             {
-                Marshal.GetNativeVariantForObject<char>('a', pNative);
-                ushort actual = Marshal.GetObjectForNativeVariant<ushort>(pNative);
-                char actualChar = (char)actual;
-                Assert.Equal('a', actualChar);
+                AssertExtensions.Throws<ArgumentException>(null, () => Marshal.GetNativeVariantForObject(obj, pNative));
+                AssertExtensions.Throws<ArgumentException>(null, () => Marshal.GetNativeVariantForObject<object>(obj, pNative));
             }
             finally
             {
@@ -83,17 +363,14 @@ namespace System.Runtime.InteropServices.Tests
 
         [Fact]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public static void CharTypeNegative()
+        public void GetNativeVariant_InvalidArray_ThrowsSafeArrayTypeMismatchException()
         {
-            // While GetNativeVariantForObject supports taking chars, GetObjectForNativeVariant will
-            // never return a char. The internal type is ushort, as mentioned above. This behavior
-            // is the same on ProjectN and Desktop CLR.
-            Variant v = new Variant();
+            var v = new Variant();
             IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
             try
             {
-                Marshal.GetNativeVariantForObject<char>('a', pNative);
-                Assert.Throws<InvalidCastException>(() => Marshal.GetObjectForNativeVariant<char>(pNative));
+                Assert.Throws<SafeArrayTypeMismatchException>(() => Marshal.GetNativeVariantForObject(new int[][] { }, pNative));
+                Assert.Throws<SafeArrayTypeMismatchException>(() => Marshal.GetNativeVariantForObject<object>(new int[][] { }, pNative));
             }
             finally
             {
@@ -101,17 +378,23 @@ namespace System.Runtime.InteropServices.Tests
             }
         }
 
-        [Fact]
+        public static IEnumerable<object[]> GetNativeVariant_VariantWrapper_TestData()
+        {
+            yield return new object[] { new VariantWrapper(null) };
+            yield return new object[] { new VariantWrapper[] { new VariantWrapper(null) } };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetNativeVariant_VariantWrapper_TestData))]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public static void StringType()
+        public void GetNativeVariant_VariantWrapper_ThrowsArgumentException(object obj)
         {
-            Variant v = new Variant();
+            var v = new Variant();
             IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
             try
             {
-                Marshal.GetNativeVariantForObject<string>("99", pNative);
-                string actual = Marshal.GetObjectForNativeVariant<string>(pNative);
-                Assert.Equal("99", actual);
+                AssertExtensions.Throws<ArgumentException>(null, () => Marshal.GetNativeVariantForObject(obj, pNative));
+                AssertExtensions.Throws<ArgumentException>(null, () => Marshal.GetNativeVariantForObject<object>(obj, pNative));
             }
             finally
             {
@@ -119,17 +402,26 @@ namespace System.Runtime.InteropServices.Tests
             }
         }
 
-        [Fact]
+        public static IEnumerable<object[]> GetNativeVariant_HandleObject_TestData()
+        {
+            yield return new object[] { new FakeSafeHandle() };
+            yield return new object[] { new FakeCriticalHandle() };
+
+            yield return new object[] { new FakeSafeHandle[] { new FakeSafeHandle() } };
+            yield return new object[] { new FakeCriticalHandle[] { new FakeCriticalHandle() } };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetNativeVariant_HandleObject_TestData))]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public static void DoubleType()
+        public void GetNativeVariant_HandleObject_ThrowsArgumentException(object obj)
         {
-            Variant v = new Variant();
+            var v = new Variant();
             IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
             try
             {
-                Marshal.GetNativeVariantForObject<double>(3.14, pNative);
-                double actual = Marshal.GetObjectForNativeVariant<double>(pNative);
-                Assert.Equal(3.14, actual);
+                AssertExtensions.Throws<ArgumentException>(null, () => Marshal.GetNativeVariantForObject(obj, pNative));
+                AssertExtensions.Throws<ArgumentException>(null, () => Marshal.GetNativeVariantForObject<object>(obj, pNative));
             }
             finally
             {
@@ -138,20 +430,91 @@ namespace System.Runtime.InteropServices.Tests
         }
 
         [Fact]
-        [PlatformSpecific(TestPlatforms.AnyUnix)]
-        public void GetNativeVariantForObject_Unix_ThrowsPlatformNotSupportedException()
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public static void GetNativeVariantForObject_CantCastToObject_ThrowsInvalidCastException()
         {
-            Assert.Throws<PlatformNotSupportedException>(() => Marshal.GetNativeVariantForObject(new object(), IntPtr.Zero));
-            Assert.Throws<PlatformNotSupportedException>(() => Marshal.GetNativeVariantForObject<int>(1, IntPtr.Zero));
+            // While GetNativeVariantForObject supports taking chars, GetObjectForNativeVariant will
+            // never return a char. The internal type is ushort, as mentioned above. This behavior
+            // is the same on ProjectN and Desktop CLR.
+            var v = new Variant();
+            IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
+            try
+            {
+                Marshal.GetNativeVariantForObject<char>('a', pNative);
+                Assert.Throws<InvalidCastException>(() => Marshal.GetObjectForNativeVariant<char>(pNative));
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(pNative);
+            }
         }
 
-        [Fact]
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetNative))]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public static void GetNativeVariantForObject_ZeroPointer_ThrowsArgumentNullException()
+        public void GetNativeVariantForObject_ObjectNotCollectible_ThrowsNotSupportedException()
         {
-            AssertExtensions.Throws<ArgumentNullException>("pDstNativeVariant", () => Marshal.GetNativeVariantForObject(new object(), IntPtr.Zero));
-            AssertExtensions.Throws<ArgumentNullException>("pDstNativeVariant", () => Marshal.GetNativeVariantForObject<int>(1, IntPtr.Zero));
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            Type type = typeBuilder.CreateType();
+
+            object o = Activator.CreateInstance(type);
+
+            var v = new Variant();
+            IntPtr pNative = Marshal.AllocHGlobal(Marshal.SizeOf(v));
+            try
+            {
+                Assert.Throws<NotSupportedException>(() => Marshal.GetNativeVariantForObject(o, pNative));
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(pNative);
+            }
+        }
+
+        public struct StructWithValue
+        {
+            public int Value;
+        }
+
+        public class ClassWithInterface : NonGenericInterface { }
+        public struct StructWithInterface : NonGenericInterface { }
+
+        public enum SByteEnum : sbyte { Value1, Value2 }
+        public enum Int16Enum : short { Value1, Value2 }
+        public enum Int32Enum : int { Value1, Value2 }
+        public enum Int64Enum : long { Value1, Value2 }
+
+        public enum ByteEnum : byte { Value1, Value2 }
+        public enum UInt16Enum : ushort { Value1, Value2 }
+        public enum UInt32Enum : uint { Value1, Value2 }
+        public enum UInt64Enum : ulong { Value1, Value2 }
+
+        public static void NonGenericMethod(int i) { }
+        public delegate void NonGenericDelegate(int i);
+
+        public class FakeSafeHandle : SafeHandle
+        {
+            public FakeSafeHandle() : base(IntPtr.Zero, false) { }
+
+            public override bool IsInvalid => throw new NotImplementedException();
+
+            protected override bool ReleaseHandle() => throw new NotImplementedException();
+
+            protected override void Dispose(bool disposing) { }
+        }
+
+        public class FakeCriticalHandle : CriticalHandle
+        {
+            public FakeCriticalHandle() : base(IntPtr.Zero) { }
+
+            public override bool IsInvalid => true;
+
+            protected override bool ReleaseHandle() => throw new NotImplementedException();
+
+            protected override void Dispose(bool disposing) { }
         }
-#pragma warning restore 618
     }
 }
+
+#pragma warning restore 618
index cd62fdb..82eedbc 100644 (file)
@@ -10,22 +10,73 @@ using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
 {
-    public class GetTypedObjectForIUnknownTests
+    public partial class GetTypedObjectForIUnknownTests
     {
-        [Fact]
+        public static IEnumerable<object> GetTypedObjectForIUnknown_RoundtrippableType_TestData()
+        {
+            yield return new object();
+            yield return 10;
+            yield return "string";
+
+            yield return new NonGenericClass();
+            yield return new NonGenericStruct();
+            yield return Int32Enum.Value1;
+
+            MethodInfo method = typeof(GetTypedObjectForIUnknownTests).GetMethod(nameof(NonGenericMethod));
+            Delegate d = method.CreateDelegate(typeof(NonGenericDelegate));
+            yield return d;
+        }
+
+        public static IEnumerable<object[]> GetTypedObjectForIUnknown_TestData()
+        {
+            foreach (object o in GetTypedObjectForIUnknown_RoundtrippableType_TestData())
+            {
+                yield return new object[] { o, o.GetType() };
+                yield return new object[] { o, typeof(GenericClass<>).GetTypeInfo().GenericTypeParameters[0] };
+                yield return new object[] { o, typeof(int).MakeByRefType() };
+
+                Type baseType = o.GetType().BaseType;
+                while (baseType != null)
+                {
+                    yield return new object[] { o, baseType };
+                    baseType = baseType.BaseType;
+                }
+            }
+
+            yield return new object[] { new ClassWithInterface(), typeof(NonGenericInterface) };
+            yield return new object[] { new StructWithInterface(), typeof(NonGenericInterface) };
+
+            yield return new object[] { new GenericClass<string>(), typeof(object) };
+            yield return new object[] { new Dictionary<string, int>(), typeof(object) };
+            yield return new object[] { new GenericStruct<string>(), typeof(object) };
+            yield return new object[] { new GenericStruct<string>(), typeof(ValueType) };
+
+            yield return new object[] { new int[] { 10 }, typeof(object) };
+            yield return new object[] { new int[] { 10 }, typeof(Array) };
+
+            yield return new object[] { new int[][] { new int[] { 10 } }, typeof(object) };
+            yield return new object[] { new int[][] { new int[] { 10 } }, typeof(Array) };
+
+            yield return new object[] { new int[,] { { 10 } }, typeof(object) };
+            yield return new object[] { new int[,] { { 10 } }, typeof(Array) };
+
+            yield return new object[] { new KeyValuePair<string, int>("key", 10), typeof(object) };
+            yield return new object[] { new KeyValuePair<string, int>("key", 10), typeof(ValueType) };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetTypedObjectForIUnknown_TestData))]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public void GetTypedObjectForIUnknown_GenericTypeParameter_ReturnsExpected()
+        public void GetTypedObjectForIUnknown_ValidPointer_ReturnsExpected(object o, Type type)
         {
-            Type type = typeof(GenericClass<>).GetTypeInfo().GenericTypeParameters[0];
-            IntPtr iUnknown = Marshal.GetIUnknownForObject(new object());
+            IntPtr ptr = Marshal.GetIUnknownForObject(o);
             try
             {
-                object typedObject = Marshal.GetTypedObjectForIUnknown(iUnknown, type);
-                Assert.IsType<object>(typedObject);
+                Assert.Equal(o, Marshal.GetTypedObjectForIUnknown(ptr, type));
             }
             finally
             {
-                Marshal.Release(iUnknown);
+                Marshal.Release(ptr);
             }
         }
 
@@ -73,38 +124,86 @@ namespace System.Runtime.InteropServices.Tests
         }
 
         [Theory]
-        [PlatformSpecific(TestPlatforms.Windows)]
         [MemberData(nameof(GetTypedObjectForIUnknown_Invalid_TestData))]
+        [PlatformSpecific(TestPlatforms.Windows)]
         public void GetTypedObjectForIUnknown_InvalidType_ThrowsArgumentException(Type type)
         {
-            IntPtr iUnknown = Marshal.GetIUnknownForObject(new object());
+            IntPtr ptr = Marshal.GetIUnknownForObject(new object());
             try
             {
-                AssertExtensions.Throws<ArgumentException>("t", () => Marshal.GetTypedObjectForIUnknown(iUnknown, type));
+                AssertExtensions.Throws<ArgumentException>("t", () => Marshal.GetTypedObjectForIUnknown(ptr, type));
             }
             finally
             {
-                Marshal.Release(iUnknown);
+                Marshal.Release(ptr);
+            }
+        }
+
+        public static IEnumerable<object[]> GetTypedObjectForIUnknownType_UncastableObject_TestData()
+        {
+            yield return new object[] { new object(), typeof(AbstractClass) };
+            yield return new object[] { new object(), typeof(NonGenericClass) };
+            yield return new object[] { new object(), typeof(NonGenericStruct) };
+            yield return new object[] { new object(), typeof(NonGenericStruct) };
+            yield return new object[] { new object(), typeof(NonGenericInterface) };
+
+            yield return new object[] { new NonGenericClass(), typeof(IFormattable) };
+            yield return new object[] { new ClassWithInterface(), typeof(IFormattable) };
+
+            yield return new object[] { new object(), typeof(int).MakePointerType() };
+
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            Type collectibleType = typeBuilder.CreateType();
+            yield return new object[] { new object(), collectibleType };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetTypedObjectForIUnknownType_UncastableObject_TestData))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public void GetTypedObjectForIUnknown_UncastableObject_ThrowsInvalidCastException(object o, Type type)
+        {
+            IntPtr ptr = Marshal.GetIUnknownForObject(o);
+            try
+            {
+                Assert.Throws<InvalidCastException>(() => Marshal.GetTypedObjectForIUnknown(ptr, type));
+            }
+            finally
+            {
+                Marshal.Release(ptr);
             }
         }
 
+        public static IEnumerable<object[]> GetTypedObjectForIUnknown_ArrayObjects_TestData()
+        {
+            yield return new object[] { new int[] { 10 } };
+            yield return new object[] { new int[][] { new int[] { 10 } } };
+            yield return new object[] { new int[,] { { 10 } } };
+        }
+
         [Theory]
+        [MemberData(nameof(GetTypedObjectForIUnknown_ArrayObjects_TestData))]
         [PlatformSpecific(TestPlatforms.Windows)]
-        [InlineData(typeof(AbstractClass))]
-        [InlineData(typeof(NonGenericClass))]
-        [InlineData(typeof(NonGenericStruct))]
-        [InlineData(typeof(NonGenericInterface))]
-        public void GetTypedObjectForIUnknown_UncastableType_ThrowsInvalidCastException(Type type)
+        public void GetTypedObjectForIUnknown_ArrayType_ThrowsBadImageFormatException(object o)
         {
-            IntPtr iUnknown = Marshal.GetIUnknownForObject(new object());
+            IntPtr ptr = Marshal.GetIUnknownForObject(o);
             try
             {
-                Assert.Throws<InvalidCastException>(() => Marshal.GetTypedObjectForIUnknown(iUnknown, type));
+                Assert.Throws<BadImageFormatException>(() => Marshal.GetTypedObjectForIUnknown(ptr, o.GetType()));
             }
             finally
             {
-                Marshal.Release(iUnknown);
+                Marshal.Release(ptr);
             }
         }
+
+        public class ClassWithInterface : NonGenericInterface { }
+        public struct StructWithInterface : NonGenericInterface { }
+
+        public static void NonGenericMethod(int i) { }
+        public delegate void NonGenericDelegate(int i);
+
+        public enum Int32Enum : int { Value1, Value2 }
     }
 }
index e9a9d5c..fe15dbd 100644 (file)
@@ -3,6 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.Emit;
 using System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
@@ -12,13 +14,44 @@ namespace System.Runtime.InteropServices.Tests
     {
         public static IEnumerable<object[]> IsComObject_TestData()
         {
+            yield return new object[] { new object() };
             yield return new object[] { 0 };
             yield return new object[] { "string" };
-            yield return new object[] { new int[0] };
+
             yield return new object[] { new NonGenericClass() };
             yield return new object[] { new GenericClass<int>() };
+            yield return new object[] { new Dictionary<string, int>() };
             yield return new object[] { new NonGenericStruct() };
             yield return new object[] { new GenericStruct<string>() };
+            yield return new object[] { Int32Enum.Value1 };
+
+            yield return new object[] { new int[] { 10 } };
+            yield return new object[] { new int[][] { new int[] { 10 } } };
+            yield return new object[] { new int[,] { { 10 } } };
+
+            MethodInfo method = typeof(IsComObjectTests).GetMethod(nameof(NonGenericMethod));
+            Delegate d = method.CreateDelegate(typeof(NonGenericDelegate));
+            yield return new object[] { d };
+
+            yield return new object[] { new KeyValuePair<string, int>("key", 10) };
+
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            Type collectibleType = typeBuilder.CreateType();
+            object collectibleObject = Activator.CreateInstance(collectibleType);
+            yield return new object[] { collectibleObject };
+            
+            ConstructorInfo comImportConstructor = typeof(ComImportAttribute).GetConstructor(new Type[0]);
+            var comImportAttributeBuilder = new CustomAttributeBuilder(comImportConstructor, new object[0]);
+
+            AssemblyBuilder comImportAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.RunAndCollect);
+            ModuleBuilder comImportModuleBuilder = comImportAssemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder comImportTypeBuilder = comImportModuleBuilder.DefineType("Type");
+            comImportTypeBuilder.SetCustomAttribute(comImportAttributeBuilder);
+
+            Type collectibleComImportObject = comImportTypeBuilder.CreateType();
+            yield return new object[] { collectibleComImportObject };
         }
 
         [Theory]
@@ -33,5 +66,10 @@ namespace System.Runtime.InteropServices.Tests
         {
             AssertExtensions.Throws<ArgumentNullException>("o", () => Marshal.IsComObject(null));
         }
+
+        public static void NonGenericMethod(int i) { }
+        public delegate void NonGenericDelegate(int i);
+
+        public enum Int32Enum : int { Value1, Value2 }
     }
 }
index ae5e2a8..c5bc193 100644 (file)
@@ -2,6 +2,10 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Reflection.Emit;
 using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
@@ -9,74 +13,54 @@ namespace System.Runtime.InteropServices.Tests
     public class OffsetOfTests
     {
         [Fact]
-        public static void NullParameter()
+        public void OffsetOf_StructField_ReturnsExpected()
         {
-            Assert.Throws<ArgumentNullException>(() => Marshal.OffsetOf(null, null));
-            Assert.Throws<ArgumentNullException>(() => Marshal.OffsetOf(new object().GetType(), null));
-            Assert.Throws<ArgumentNullException>(() => Marshal.OffsetOf(null, "abcd"));
+            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(typeof(SomeStruct), nameof(SomeStruct.var)));
         }
 
         [Fact]
-        public void NonExistField()
+        public void OffsetOf_ClassWithExplicitLayout_ReturnsExpected()
         {
-            Assert.Throws<ArgumentException>(() => Marshal.OffsetOf(typeof(NonExistField), "NonExistField"));
+            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(typeof(MySystemTime), nameof(MySystemTime.wYear)));
+            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(typeof(MySystemTime), nameof(MySystemTime.wHour)));
+            Assert.Equal(new IntPtr(14), Marshal.OffsetOf(typeof(MySystemTime), nameof(MySystemTime.wMilliseconds)));
         }
 
         [Fact]
-        public void NoLayoutClass()
+        public void OffsetOf_ClassWithSequentialLayout_ReturnsExpected()
         {
-            Assert.Throws<ArgumentException>(() => Marshal.OffsetOf(typeof(NoLayoutPoint), "x"));
+            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(typeof(MyPoint), nameof(MyPoint.x)));
+            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(typeof(MyPoint), nameof(MyPoint.y)));
         }
 
         [Fact]
-        public void StructField()
-        {
-            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(typeof(SomeStruct), "var"));
-        }
-
-        [Fact]
-        public void ClassExplicitField()
-        {
-            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(typeof(MySystemTime), "wYear"));
-            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(typeof(MySystemTime), "wHour"));
-            Assert.Equal(new IntPtr(14), Marshal.OffsetOf(typeof(MySystemTime), "wMilliseconds"));
-        }
-
-        [Fact]
-        public void ClassSequentialField()
-        {
-            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(typeof(MyPoint), "x"));
-            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(typeof(MyPoint), "y"));
-        }
-
-        [Fact]
-        public void TestExplicitLayout()
+        public void OffsetOf_ExplicitLayout_ReturnsExpected()
         {
             Type t = typeof(ExplicitLayoutTest);
             Assert.Equal(56, Marshal.SizeOf(t));
-            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, "m_short1"));
-            Assert.Equal(new IntPtr(2), Marshal.OffsetOf(t, "m_short2"));
-
-            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, "union1_byte1"));
-            Assert.Equal(new IntPtr(5), Marshal.OffsetOf(t, "union1_byte2"));
-            Assert.Equal(new IntPtr(6), Marshal.OffsetOf(t, "union1_short1"));
-            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, "union1_int1"));
-            Assert.Equal(new IntPtr(12), Marshal.OffsetOf(t, "union1_int2"));
-            Assert.Equal(new IntPtr(16), Marshal.OffsetOf(t, "union1_double1"));
-
-            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, "union2_ushort1"));
-            Assert.Equal(new IntPtr(6), Marshal.OffsetOf(t, "union2_ushort2"));
-            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, "union3_int1"));
-            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, "union3_decimal1"));
-
-            Assert.Equal(new IntPtr(24), Marshal.OffsetOf(t, "m_ushort1"));
-            Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, "m_decimal1"));
-            Assert.Equal(new IntPtr(48), Marshal.OffsetOf(t, "m_char1"));
+            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.m_short1)));
+            Assert.Equal(new IntPtr(2), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.m_short2)));
+
+            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union1_byte1)));
+            Assert.Equal(new IntPtr(5), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union1_byte2)));
+            Assert.Equal(new IntPtr(6), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union1_short1)));
+            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union1_int1)));
+            Assert.Equal(new IntPtr(12), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union1_int2)));
+            Assert.Equal(new IntPtr(16), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union1_double1)));
+
+            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union2_ushort1)));
+            Assert.Equal(new IntPtr(6), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union2_ushort2)));
+            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union3_int1)));
+            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.union3_decimal1)));
+
+            Assert.Equal(new IntPtr(24), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.m_ushort1)));
+            Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.m_decimal1)));
+            Assert.Equal(new IntPtr(48), Marshal.OffsetOf(t, nameof(ExplicitLayoutTest.m_char1)));
         }
 
         [Fact]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public void TestFieldAlignment_Windows()
+        public void OffsetOf_ValidField_ReturnsExpected()
         {
             Type t = typeof(FieldAlignmentTest);
             if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || (RuntimeInformation.ProcessArchitecture != Architecture.X86))
@@ -88,41 +72,41 @@ namespace System.Runtime.InteropServices.Tests
                 Assert.Equal(72, Marshal.SizeOf(t));
             }
 
-            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, "m_byte1"));
-            Assert.Equal(new IntPtr(2), Marshal.OffsetOf(t, "m_short1"));
-            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, "m_short2"));
-            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, "m_int1"));
-            Assert.Equal(new IntPtr(12), Marshal.OffsetOf(t, "m_byte2"));
-            Assert.Equal(new IntPtr(16), Marshal.OffsetOf(t, "m_int2"));
+            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_byte1)));
+            Assert.Equal(new IntPtr(2), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_short1)));
+            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_short2)));
+            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_int1)));
+            Assert.Equal(new IntPtr(12), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_byte2)));
+            Assert.Equal(new IntPtr(16), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_int2)));
 
             if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || (RuntimeInformation.ProcessArchitecture != Architecture.X86))
             {
-                Assert.Equal(new IntPtr(24), Marshal.OffsetOf(t, "m_double1"));
-                Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, "m_char1"));
-                Assert.Equal(new IntPtr(33), Marshal.OffsetOf(t, "m_char2"));
-                Assert.Equal(new IntPtr(34), Marshal.OffsetOf(t, "m_char3"));
-                Assert.Equal(new IntPtr(40), Marshal.OffsetOf(t, "m_double2"));
-                Assert.Equal(new IntPtr(48), Marshal.OffsetOf(t, "m_byte3"));
-                Assert.Equal(new IntPtr(49), Marshal.OffsetOf(t, "m_byte4"));
-                Assert.Equal(new IntPtr(56), Marshal.OffsetOf(t, "m_decimal1"));
-                Assert.Equal(new IntPtr(72), Marshal.OffsetOf(t, "m_char4"));
+                Assert.Equal(new IntPtr(24), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_double1)));
+                Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char1)));
+                Assert.Equal(new IntPtr(33), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char2)));
+                Assert.Equal(new IntPtr(34), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char3)));
+                Assert.Equal(new IntPtr(40), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_double2)));
+                Assert.Equal(new IntPtr(48), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_byte3)));
+                Assert.Equal(new IntPtr(49), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_byte4)));
+                Assert.Equal(new IntPtr(56), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_decimal1)));
+                Assert.Equal(new IntPtr(72), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char4)));
             }
             else
             {
-                Assert.Equal(new IntPtr(20), Marshal.OffsetOf(t, "m_double1"));
-                Assert.Equal(new IntPtr(28), Marshal.OffsetOf(t, "m_char1"));
-                Assert.Equal(new IntPtr(29), Marshal.OffsetOf(t, "m_char2"));
-                Assert.Equal(new IntPtr(30), Marshal.OffsetOf(t, "m_char3"));
-                Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, "m_double2"));
-                Assert.Equal(new IntPtr(40), Marshal.OffsetOf(t, "m_byte3"));
-                Assert.Equal(new IntPtr(41), Marshal.OffsetOf(t, "m_byte4"));
-                Assert.Equal(new IntPtr(48), Marshal.OffsetOf(t, "m_decimal1"));
-                Assert.Equal(new IntPtr(64), Marshal.OffsetOf(t, "m_char4"));
+                Assert.Equal(new IntPtr(20), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_double1)));
+                Assert.Equal(new IntPtr(28), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char1)));
+                Assert.Equal(new IntPtr(29), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char2)));
+                Assert.Equal(new IntPtr(30), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char3)));
+                Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_double2)));
+                Assert.Equal(new IntPtr(40), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_byte3)));
+                Assert.Equal(new IntPtr(41), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_byte4)));
+                Assert.Equal(new IntPtr(48), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_decimal1)));
+                Assert.Equal(new IntPtr(64), Marshal.OffsetOf(t, nameof(FieldAlignmentTest.m_char4)));
             }
         }
 
         [Fact]
-        public void TestFieldAlignment_Decimal()
+        public void OffsetOf_Decimal_ReturnsExpected()
         {
             Type t = typeof(FieldAlignmentTest_Decimal);
 
@@ -135,47 +119,47 @@ namespace System.Runtime.InteropServices.Tests
                 Assert.Equal(88, Marshal.SizeOf(t));
             }
 
-            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, "b"));
-            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, "p"));
+            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Decimal.b)));
+            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Decimal.p)));
 
             if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || (RuntimeInformation.ProcessArchitecture != Architecture.X86))
             {
-                Assert.Equal(new IntPtr(88), Marshal.OffsetOf(t, "s"));
+                Assert.Equal(new IntPtr(88), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Decimal.s)));
             }
             else
             {
-                Assert.Equal(new IntPtr(80), Marshal.OffsetOf(t, "s"));
+                Assert.Equal(new IntPtr(80), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Decimal.s)));
             }
         }
 
         [Fact]
-        public void TestFieldAlignment_Guid()
+        public void OffsetOf_Guid_ReturnsExpected()
         {
             Type t = typeof(FieldAlignmentTest_Guid);
             Assert.Equal(24, Marshal.SizeOf(t));
 
-            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, "b"));
-            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, "g"));
-            Assert.Equal(new IntPtr(20), Marshal.OffsetOf(t, "s"));
+            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Guid.b)));
+            Assert.Equal(new IntPtr(4), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Guid.g)));
+            Assert.Equal(new IntPtr(20), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Guid.s)));
         }
 
         [Fact]
         [PlatformSpecific(TestPlatforms.Windows)]
-        public void TestFieldAlignment_Variant()
+        public void OffsetOf_Variant_ReturnsExpected()
         {
             Type t = typeof(FieldAlignmentTest_Variant);
 
-            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, "b"));
-            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, "v"));
+            Assert.Equal(new IntPtr(0), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Variant.b)));
+            Assert.Equal(new IntPtr(8), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Variant.v)));
 
             if (IntPtr.Size == 4)
             {
-                Assert.Equal(new IntPtr(24), Marshal.OffsetOf(t, "s"));
+                Assert.Equal(new IntPtr(24), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Variant.s)));
                 Assert.Equal(32, Marshal.SizeOf(t));
             }
             else if (IntPtr.Size == 8)
             {
-                Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, "s"));
+                Assert.Equal(new IntPtr(32), Marshal.OffsetOf(t, nameof(FieldAlignmentTest_Variant.s)));
                 Assert.Equal(40, Marshal.SizeOf(t));
             }
             else
@@ -185,21 +169,169 @@ namespace System.Runtime.InteropServices.Tests
         }
 
         [Fact]
-        public void NonGenericOffEqualsGenericOffset()
+        public void OffsetOf_Generic_MatchedNonGeneric()
         {
             IntPtr nonGenericOffsetCall = Marshal.OffsetOf(typeof(SomeStruct), "var");
             IntPtr genericOffsetCall = Marshal.OffsetOf<SomeStruct>("var");
             Assert.Equal(nonGenericOffsetCall, genericOffsetCall);
+        }
+
+        [Fact]
+        public void OffsetOf_NullType_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("t", () => Marshal.OffsetOf(null, null));
+            AssertExtensions.Throws<ArgumentNullException>("t", () => Marshal.OffsetOf(null, "abcd"));
+        }
+
+        [Fact]
+        public void OffsetOf_NullFieldName_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>(null, () => Marshal.OffsetOf(new object().GetType(), null));
+            AssertExtensions.Throws<ArgumentNullException>(null, () => Marshal.OffsetOf<object>(null));
+        }
+
+        [Fact]
+        public void OffsetOf_NoSuchFieldName_ThrowsArgumentException()
+        {
+            AssertExtensions.Throws<ArgumentException>("fieldName", () => Marshal.OffsetOf(typeof(NonExistField), "NonExistField"));
+            AssertExtensions.Throws<ArgumentException>("fieldName", () => Marshal.OffsetOf<NonExistField>("NonExistField"));
+        }
+
+        [Fact]
+        public void OffsetOf_NonRuntimeField_ThrowsArgumentException()
+        {
+            AssertExtensions.Throws<ArgumentException>("fieldName", () => Marshal.OffsetOf(new NonRuntimeType(), "Field"));
+        }
 
-            Assert.Throws<ArgumentException>(() => Marshal.OffsetOf(typeof(StructWithFxdLPSTRSAFld), "Arr"));
+        public static IEnumerable<object[]> OffsetOf_NotMarshallable_TestData()
+        {
+            yield return new object[] { typeof(StructWithFxdLPSTRSAFld), nameof(StructWithFxdLPSTRSAFld.Arr) };
+        }
+
+        [Theory]
+        [MemberData(nameof(OffsetOf_NotMarshallable_TestData))]
+        public void OffsetOf_NotMarshallable_ThrowsArgumentException(Type t, string fieldName)
+        {
+            AssertExtensions.Throws<ArgumentException>(null, () => Marshal.OffsetOf(t, fieldName));
+        }
+
+        [Fact]
+        public void OffsetOf_NoLayoutPoint_ThrowsArgumentException()
+        {
+            AssertExtensions.Throws<ArgumentException>(null, () => Marshal.OffsetOf(typeof(NoLayoutPoint), nameof(NoLayoutPoint.x)));
+            AssertExtensions.Throws<ArgumentException>(null, () => Marshal.OffsetOf<NoLayoutPoint>(nameof(NoLayoutPoint.x)));
+        }
+
+        public class NonRuntimeType : Type
+        {
+            public override FieldInfo GetField(string name, BindingFlags bindingAttr)
+            {
+                return new NonRuntimeFieldInfo();
+            }
+
+            public override Assembly Assembly => throw new NotImplementedException();
+
+            public override string AssemblyQualifiedName => throw new NotImplementedException();
+
+            public override Type BaseType => throw new NotImplementedException();
+
+            public override string FullName => throw new NotImplementedException();
+
+            public override Guid GUID => throw new NotImplementedException();
+
+            public override Module Module => throw new NotImplementedException();
+
+            public override string Namespace => throw new NotImplementedException();
+
+            public override Type UnderlyingSystemType => throw new NotImplementedException();
+
+            public override string Name => throw new NotImplementedException();
+
+            public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException();
+
+            public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException();
+
+            public override Type GetElementType() => throw new NotImplementedException();
+
+            public override EventInfo GetEvent(string name, BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override EventInfo[] GetEvents(BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override FieldInfo[] GetFields(BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override Type GetInterface(string name, bool ignoreCase) => throw new NotImplementedException();
+
+            public override Type[] GetInterfaces() => throw new NotImplementedException();
+
+            public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override Type GetNestedType(string name, BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override Type[] GetNestedTypes(BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => throw new NotImplementedException();
+
+            public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) => throw new NotImplementedException();
+
+            public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException();
+
+            protected override TypeAttributes GetAttributeFlagsImpl() => throw new NotImplementedException();
+
+            protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException();
+
+            protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException();
+
+            protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException();
+
+            protected override bool HasElementTypeImpl() => throw new NotImplementedException();
+
+            protected override bool IsArrayImpl() => throw new NotImplementedException();
+
+            protected override bool IsByRefImpl() => throw new NotImplementedException();
+
+            protected override bool IsCOMObjectImpl() => throw new NotImplementedException();
+
+            protected override bool IsPointerImpl() => throw new NotImplementedException();
+
+            protected override bool IsPrimitiveImpl() => throw new NotImplementedException();
+        }
+
+        public class NonRuntimeFieldInfo : FieldInfo
+        {
+            public override FieldAttributes Attributes => throw new NotImplementedException();
+
+            public override RuntimeFieldHandle FieldHandle => throw new NotImplementedException();
+
+            public override Type FieldType => throw new NotImplementedException();
+
+            public override Type DeclaringType => throw new NotImplementedException();
+
+            public override string Name => throw new NotImplementedException();
+
+            public override Type ReflectedType => throw new NotImplementedException();
+
+            public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException();
+
+            public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException();
+
+            public override object GetValue(object obj) => throw new NotImplementedException();
+
+            public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException();
+
+            public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture) => throw new NotImplementedException();
         }
     }
+
 #pragma warning disable 169, 649, 618
     [StructLayout(LayoutKind.Sequential)]
     public struct StructWithFxdLPSTRSAFld
     {
         [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 0)]
-        public String[] Arr;
+        public string[] Arr;
     }
 
     public struct SomeStruct
@@ -263,9 +395,9 @@ namespace System.Runtime.InteropServices.Tests
         [FieldOffset(6)]
         public short union1_short1; // 2 bytes
         [FieldOffset(8)]
-        public Int32 union1_int1; // 4 bytes
+        public int union1_int1; // 4 bytes
         [FieldOffset(12)]
-        public Int32 union1_int2; // 4 bytes
+        public int union1_int2; // 4 bytes
         [FieldOffset(16)]
         public double union1_double1; // 8 bytes
 
@@ -274,7 +406,7 @@ namespace System.Runtime.InteropServices.Tests
         [FieldOffset(6)]
         public ushort union2_ushort2; // 2 bytes
         [FieldOffset(8)]
-        public Int32 union3_int1; // 4 bytes
+        public int union3_int1; // 4 bytes
         [FieldOffset(8)]
         public decimal union3_decimal1; // 16 bytes
 
@@ -299,11 +431,11 @@ namespace System.Runtime.InteropServices.Tests
         public short m_short2; // 2 bytes
                                // 2 bytes of padding
 
-        public Int32 m_int1; // 4 bytes
+        public int m_int1; // 4 bytes
         public byte m_byte2; // 1 byte
                              // 3 bytes of padding
 
-        public Int32 m_int2; // 4 bytes
+        public int m_int2; // 4 bytes
                              // 4 bytes of padding (0 bytes on x86/Unix according System V ABI as double 4-byte aligned)
 
         public double m_double1; // 8 bytes
index ffd12de..7c9292c 100644 (file)
@@ -2,7 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using System.Collections.Generic;
 using System.Globalization;
 using System.Reflection;
 using Xunit;
index 512acda..5d902c5 100644 (file)
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
 {
     public class PtrToStructureTests
     {
+        [Fact]
+        public void StructureToPtr_NonGenericType_ReturnsExpected()
+        {
+            var structure = new SomeTestStruct
+            {
+                i = 10,
+                s = "hello"
+            };
+
+            int size = Marshal.SizeOf(structure);
+            IntPtr ptr = Marshal.AllocHGlobal(size);
+            try
+            {
+                Marshal.StructureToPtr(structure, ptr, false);
+
+                SomeTestStruct result = Assert.IsType<SomeTestStruct>(Marshal.PtrToStructure(ptr, typeof(SomeTestStruct)));
+                Assert.Equal(10, result.i);
+                Assert.Equal("hello", result.s);
+            }
+            finally
+            {
+                Marshal.DestroyStructure(ptr, structure.GetType());
+                Marshal.FreeHGlobal(ptr);
+            }
+        }
+
+        [Fact]
+        public void StructureToPtr_GenericType_ReturnsExpected()
+        {
+            var structure = new SomeTestStruct
+            {
+                i = 10,
+                s = "hello"
+            };
+
+            int size = Marshal.SizeOf(structure);
+            IntPtr ptr = Marshal.AllocHGlobal(size);
+            try
+            {
+                Marshal.StructureToPtr(structure, ptr, false);
+
+                SomeTestStruct result = Marshal.PtrToStructure<SomeTestStruct>(ptr);
+                Assert.Equal(10, result.i);
+                Assert.Equal("hello", result.s);
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(ptr);
+            }
+        }
+
+        [Fact]
+        public void StructureToPtr_NonGenericObject_ReturnsExpected()
+        {
+            var structure = new SomeTestStruct
+            {
+                i = 10,
+                s = "hello"
+            };
+
+            int size = Marshal.SizeOf(structure);
+            IntPtr ptr = Marshal.AllocHGlobal(size);
+            try
+            {
+                Marshal.StructureToPtr(structure, ptr, false);
+
+                var result = new SequentialClass();
+                Marshal.PtrToStructure(ptr, (object)result);
+                Assert.Equal(10, result.i);
+                Assert.Equal("hello", result.s);
+            }
+            finally
+            {
+                Marshal.FreeHGlobal(ptr);
+            }
+        }
+
+        [Fact]
+        public void StructureToPtr_GenericObject_ReturnsExpected()
+        {
+            var structure = new SomeTestStruct
+            {
+                i = 10,
+                s = "hello"
+            };
+
+            int size = Marshal.SizeOf(structure);
+            IntPtr ptr = Marshal.AllocHGlobal(size);
+            try
+            {
+                Marshal.StructureToPtr(structure, ptr, false);
+
+                var result = new SequentialClass();
+                Marshal.PtrToStructure(ptr, result);
+                Assert.Equal(10, result.i);
+                Assert.Equal("hello", result.s);
+            }
+            finally
+            {
+                Marshal.DestroyStructure(ptr, structure.GetType());
+                Marshal.FreeHGlobal(ptr);
+            }
+        }
+
+        [Fact]
+        public void PtrToStructure_ZeroPointerWithType_ReturnsNull()
+        {
+            Assert.Null(Marshal.PtrToStructure(IntPtr.Zero, typeof(SomeTestStruct)));
+            Assert.Null(Marshal.PtrToStructure<NonGenericClass>(IntPtr.Zero));
+            Assert.Throws<NullReferenceException>(() => Marshal.PtrToStructure<SomeTestStruct>(IntPtr.Zero));
+        }
+
+        [Fact]
+        public void PtrToStructure_ZeroPointer_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.PtrToStructure(IntPtr.Zero, (object)new SomeTestStruct()));
+            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.PtrToStructure(IntPtr.Zero, new SomeTestStruct()));
+        }
+
+        [Fact]
+        public void PtrToStructure_NullStructure_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.PtrToStructure((IntPtr)1, (object)null));
+            AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.PtrToStructure<object>((IntPtr)1, null));
+        }
+
+        public static IEnumerable<object[]> PtrToStructure_GenericClass_TestData()
+        {
+            yield return new object[] { new GenericClass<string>() };
+            yield return new object[] { new GenericStruct<string>() };
+        }
+
+        [Theory]
+        [MemberData(nameof(PtrToStructure_GenericClass_TestData))]
+        public void PtrToStructure_GenericObject_ThrowsArgumentException(object o)
+        {
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.PtrToStructure((IntPtr)1, o));
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.PtrToStructure<object>((IntPtr)1, o));
+        }
+        
+        public static IEnumerable<object[]> PtrToStructure_ObjectNotValueClass_TestData()
+        {
+            yield return new object[] { new NonGenericStruct() };
+            yield return new object[] { Int32Enum.Value1 };
+        }
+
+        [Theory]
+        [MemberData(nameof(PtrToStructure_ObjectNotValueClass_TestData))]
+        public void PtrToStructure_ObjectNotValueClass_ThrowsArgumentException(object structure)
+        {
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.PtrToStructure((IntPtr)1, structure));
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.PtrToStructure<object>((IntPtr)1, structure));
+        }
+
+        public static IEnumerable<object[]> PtrToStructure_ObjectNotBlittable_TestData()
+        {
+            yield return new object[] { new NonGenericClass() };
+        }
+
+        [Theory]
+        [MemberData(nameof(PtrToStructure_ObjectNotBlittable_TestData))]
+        public void PtrToStructure_ObjectNoBlittable_ThrowsArgumentException(object structure)
+        {
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.PtrToStructure((IntPtr)1, structure));
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.PtrToStructure<object>((IntPtr)1, structure));
+        }
+
+        [Fact]
+        public void PtrToStructure_NullStructureType_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("structureType", () => Marshal.PtrToStructure((IntPtr)1, null));
+        }
+
+        public static IEnumerable<object[]> PtrToStructure_GenericType_TestData()
+        {
+            yield return new object[] { typeof(GenericClass<string>) };
+            yield return new object[] { typeof(GenericClass<>) };
+            yield return new object[] { typeof(GenericStruct<string>) };
+            yield return new object[] { typeof(GenericStruct<>) };
+            yield return new object[] { typeof(GenericInterface<string>) };
+            yield return new object[] { typeof(GenericInterface<>) };
+        }
+
+        [Theory]
+        [MemberData(nameof(PtrToStructure_GenericType_TestData))]
+        public void PtrToStructure_GenericType_ThrowsArgumentException(Type structureType)
+        {
+            AssertExtensions.Throws<ArgumentException>("structureType", () => Marshal.PtrToStructure((IntPtr)1, structureType));
+        }
+
+        [Fact]
+        public void PtrToStructure_NonRuntimeType_ThrowsArgumentException()
+        {
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.Run);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            AssertExtensions.Throws<ArgumentException>("structureType", "type", () => Marshal.PtrToStructure((IntPtr)1, (Type)typeBuilder));
+        }
+
+        public static IEnumerable<object[]> PtrToStructure_NonBlittableType_TestData()
+        {
+            yield return new object[] { typeof(AutoLayoutStruct) };
+            yield return new object[] { typeof(NonGenericClass) };
+            yield return new object[] { typeof(AbstractClass) };
+        }
+
+        [Theory]
+        [MemberData(nameof(PtrToStructure_NonBlittableType_TestData))]
+        public void PtrToStructure_NonBlittablType_ThrowsArgumentException(Type structureType)
+        {
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.PtrToStructure((IntPtr)1, structureType));
+        }
+
+        public static IEnumerable<object[]> PtrToStructure_CantCreateType_TestData()
+        {
+            yield return new object[] { typeof(GenericClass<>).GetTypeInfo().GenericTypeParameters[0], typeof(ArgumentException) };
+            yield return new object[] { typeof(int).MakePointerType(), typeof(MissingMethodException) };
+            yield return new object[] { typeof(int).MakeByRefType(), typeof(MissingMethodException) };
+        }
+
+        [Theory]
+        [MemberData(nameof(PtrToStructure_CantCreateType_TestData))]
+        public void PtrToStructure_CantCreateType_ThrowsArgumentException(Type structureType, Type exceptionType)
+        {
+            Assert.Throws(exceptionType, () => Marshal.PtrToStructure((IntPtr)1, structureType));
+        }
+
         [StructLayout(LayoutKind.Sequential)]
         public struct SomeTestStruct
         {
             public int i;
-            public String s;
+            public string s;
         }
 
-        [Fact]
-        public void PtrToStructureTest()
+        [StructLayout(LayoutKind.Auto)]
+        public struct AutoLayoutStruct
         {
-            IntPtr ip;
-            SomeTestStruct someTestStruct = new SomeTestStruct();
-            
-            ip = IntPtr.Zero;
-            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.PtrToStructure(ip, someTestStruct));
-
-            ip = new IntPtr(123);
-            AssertExtensions.Throws<ArgumentNullException>("structureType", () => Marshal.PtrToStructure(ip, null));
+            public int i;
+        }
 
-            ip = new IntPtr(123);
-            Assert.Throws<ArgumentException>(() => Marshal.PtrToStructure<SomeTestStruct>(ip, someTestStruct));
+        [StructLayout(LayoutKind.Sequential)]
+        public class SequentialClass
+        {
+            public int i;
+            public string s;
         }
+
+        public enum Int32Enum : int { Value1, Value2 }
     }
 }
index 76298bc..39c5556 100644 (file)
@@ -2,12 +2,84 @@
 // 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 System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
 {
     public class SizeOfTests
     {
+        [Fact]
+        public void SizeOf_StructWithEnumArray_ReturnsExpected()
+        {
+            var s = new TestStructWithEnumArray
+            {
+                ArrayOfEnum = new TestEnum[] { TestEnum.Red, TestEnum.Green, TestEnum.Blue }
+            };
+
+            Assert.Equal(12, Marshal.SizeOf((object)s));
+            Assert.Equal(12, Marshal.SizeOf(s));
+            Assert.Equal(12, Marshal.SizeOf(typeof(TestStructWithEnumArray)));
+            Assert.Equal(12, Marshal.SizeOf<TestStructWithEnumArray>());
+        }
+
+        [Fact]
+        public void SizeOf_Object_ReturnsExpected()
+        {
+            SomeTestStruct someTestStruct = new SomeTestStruct();
+            Assert.NotEqual(0, Marshal.SizeOf(someTestStruct.GetType()));
+        }
+
+        [Fact]
+        public void SizeOf_Pointer_ReturnsExpected()
+        {
+            Assert.Equal(IntPtr.Size, Marshal.SizeOf(typeof(int).MakePointerType()));
+        }
+
+        [Fact]
+        public void SizeOf_NullType_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("t", () => Marshal.SizeOf(null));
+        }
+
+        [Fact]
+        public void SizeOf_NullStructure_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.SizeOf((object)null));
+            AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.SizeOf<string>(null));
+        }
+
+        public static IEnumerable<object[]> SizeOf_InvalidType_TestData()
+        {
+            yield return new object[] { typeof(int).MakeByRefType(), null };
+            
+            yield return new object[] { typeof(GenericClass<>), "t" };
+            yield return new object[] { typeof(GenericClass<string>), "t" };
+            yield return new object[] { typeof(GenericStruct<>), "t" };
+            yield return new object[] { typeof(GenericStruct<string>), "t" };
+            yield return new object[] { typeof(GenericInterface<>), "t" };
+            yield return new object[] { typeof(GenericInterface<string>), "t" };
+
+            yield return new object[] { typeof(GenericClass<>).GetTypeInfo().GenericTypeParameters[0], null };
+
+            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.Run);
+            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
+            TypeBuilder typeBuilder = moduleBuilder.DefineType("Type");
+            yield return new object[] { typeBuilder, "t" };
+
+            yield return new object[] { typeof(TestStructWithFxdLPSTRSAFld), null };
+        }
+
+        [Theory]
+        [MemberData(nameof(SizeOf_InvalidType_TestData))]
+        public void SizeOf_InvalidType_ThrowsArgumentException(Type type, string paramName)
+        {
+            AssertExtensions.Throws<ArgumentException>(paramName, () => Marshal.SizeOf(type));
+        }
+
         public struct TestStructWithEnumArray
         {
             [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
@@ -16,50 +88,23 @@ namespace System.Runtime.InteropServices.Tests
 
         public enum TestEnum
         {
-            red,
-            green,
-            blue
+            Red,
+            Green,
+            Blue
         }
 
         [StructLayout(LayoutKind.Sequential)]
         public struct SomeTestStruct
         {
             public int i;
-            public String s;
+            public string s;
         }
 
         [StructLayout(LayoutKind.Sequential)]
         public struct TestStructWithFxdLPSTRSAFld
         {
             [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 0)]
-            public String[] Arr;
-        }
-
-        [Fact]
-        public void SizeOfStructWithEnumArray()
-        {
-            TestStructWithEnumArray s = new TestStructWithEnumArray();
-            s.ArrayOfEnum = new TestEnum[3];
-            s.ArrayOfEnum[0] = TestEnum.red;
-            s.ArrayOfEnum[1] = TestEnum.green;
-            s.ArrayOfEnum[2] = TestEnum.blue;
-            int retsize = Marshal.SizeOf(s.GetType());
-            Assert.Equal(12, retsize);
-
-            retsize = 0;
-            retsize = Marshal.SizeOf(typeof(TestStructWithEnumArray));
-            int genericRetsize = Marshal.SizeOf<TestStructWithEnumArray>();
-            Assert.Equal(12, retsize);
-            Assert.Equal(retsize, genericRetsize);
-        }
-
-        [Fact]
-        public void SizeOfStructTest()
-        {
-            SomeTestStruct someTestStruct = new SomeTestStruct();
-            AssertExtensions.Throws<ArgumentNullException>("t", () => Marshal.SizeOf(null));
-            Assert.Throws<ArgumentException>(() => Marshal.SizeOf(typeof(TestStructWithFxdLPSTRSAFld)));
-            Marshal.SizeOf(someTestStruct.GetType());
+            public string[] Arr;
         }
     }
 }
index e327c21..82198f0 100644 (file)
@@ -2,72 +2,24 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
+using System.Runtime.InteropServices.Tests.Common;
 using Xunit;
 
 namespace System.Runtime.InteropServices.Tests
 {
     public class StructureToPtrTests
     {
-        public struct StructWithIntField
-        {
-            public int value;
-        }
-
-        public struct StructWithByValArray
-        {
-            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
-            public StructWithIntField[] array;
-        }
-
-        public struct StructWithBoolArray
-        {
-            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
-            public bool[] array;
-        }
-
-        public struct StructWithDateArray
-        {
-            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
-            public DateTime[] array;
-        }
-
-        [StructLayout(LayoutKind.Auto)]
-        public struct SomeTestStruct_Auto
-        {
-            public int i;
-        }
-
-        [Fact]
-        public void AutoLayoutStructureTest()
-        {
-            var someTs_Auto = new SomeTestStruct_Auto();
-            ArgumentException ex = AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.StructureToPtr(someTs_Auto, new IntPtr(123), true));
-        }
-
         [Fact]
-        public void NullParameter()
-        {
-            IntPtr ip = IntPtr.Zero;
-            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.StructureToPtr<SomeTestStruct_Auto>(new SomeTestStruct_Auto(), ip, true));
-
-            ip = new IntPtr(123);
-            AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.StructureToPtr<Object>(null, ip, true));
-        }
-
-        [Fact]
-        public void VerifyByValBoolArray()
+        public void StructureToPtr_ByValBoolArray_Success()
         {
             var structure1 = new StructWithBoolArray()
             {
-                array = new bool[]
-                {
-                    true,true,true,true
-                }
+                array = new bool[] { true, true, true, true }
             };
 
             int size = Marshal.SizeOf(structure1);
-            IntPtr memory = Marshal.AllocHGlobal(size + sizeof(Int32));
-
+            IntPtr memory = Marshal.AllocHGlobal(size + sizeof(int));
             try
             {
                 Marshal.WriteInt32(memory, size, 0xFF);
@@ -82,10 +34,9 @@ namespace System.Runtime.InteropServices.Tests
         }
 
         [Fact]
-        public void VerifyByValArrayInStruct()
+        public void StructureToPtr_ByValArrayInStruct_Success()
         {
-            // equal
-            var structure1 = new StructWithByValArray()
+            var structure = new StructWithByValArray()
             {
                 array = new StructWithIntField[]
                 {
@@ -96,90 +47,176 @@ namespace System.Runtime.InteropServices.Tests
                     new StructWithIntField { value = 5 }
                 }
             };
-            int size = Marshal.SizeOf(structure1);
+            int size = Marshal.SizeOf(structure);
             IntPtr memory = Marshal.AllocHGlobal(size);
             try
             {
-                Marshal.StructureToPtr(structure1, memory, false);
-                Marshal.StructureToPtr(structure1, memory, true);
+                Marshal.StructureToPtr(structure, memory, false);
+                Marshal.StructureToPtr(structure, memory, true);
             }
             finally
             {
                 Marshal.FreeHGlobal(memory);
             }
+        }
 
-            // underflow
-            var structure2 = new StructWithByValArray()
+        [Fact]
+        public void StructureToPtr_OverflowByValArrayInStruct_Success()
+        {
+            var structure = new StructWithByValArray()
             {
                 array = new StructWithIntField[]
                 {
                     new StructWithIntField { value = 1 },
                     new StructWithIntField { value = 2 },
                     new StructWithIntField { value = 3 },
-                    new StructWithIntField { value = 4 }
+                    new StructWithIntField { value = 4 },
+                    new StructWithIntField { value = 5 },
+                    new StructWithIntField { value = 6 }
                 }
             };
-            size = Marshal.SizeOf(structure2);
-            memory = Marshal.AllocHGlobal(size);
+
+            int size = Marshal.SizeOf(structure);
+            IntPtr memory = Marshal.AllocHGlobal(size);
             try
             {
-                Assert.Throws<ArgumentException>(() => Marshal.StructureToPtr(structure2, memory, false));
-                Assert.Throws<ArgumentException>(() => Marshal.StructureToPtr(structure2, memory, true));
+                Marshal.StructureToPtr(structure, memory, false);
+                Marshal.StructureToPtr(structure, memory, true);
             }
             finally
             {
                 Marshal.FreeHGlobal(memory);
             }
+        }
 
-            // overflow
-            var structure3 = new StructWithByValArray()
+        [Fact]
+        public void StructureToPtr_ByValDateArray_Success()
+        {
+            var structure = new StructWithDateArray()
             {
-                array = new StructWithIntField[]
+                array = new DateTime[]
                 {
-                    new StructWithIntField { value = 1 },
-                    new StructWithIntField { value = 2 },
-                    new StructWithIntField { value = 3 },
-                    new StructWithIntField { value = 4 },
-                    new StructWithIntField { value = 5 },
-                    new StructWithIntField { value = 6 }
+                    DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now
                 }
             };
 
-            size = Marshal.SizeOf(structure3);
-            memory = Marshal.AllocHGlobal(size);
+            int size = Marshal.SizeOf(structure);
+            IntPtr memory = Marshal.AllocHGlobal(size);
             try
             {
-                Marshal.StructureToPtr(structure3, memory, false);
-                Marshal.StructureToPtr(structure3, memory, true);
+                Marshal.StructureToPtr(structure, memory, false);
+                Marshal.StructureToPtr(structure, memory, true);
             }
             finally
             {
+                Marshal.DestroyStructure(memory, structure.GetType());
                 Marshal.FreeHGlobal(memory);
             }
         }
 
         [Fact]
-        public void VerfiyByValDateArray()
+        public void StructureToPtr_NullPtr_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.StructureToPtr((object)new SomeTestStruct_Auto(), IntPtr.Zero, fDeleteOld: true));
+            AssertExtensions.Throws<ArgumentNullException>("ptr", () => Marshal.StructureToPtr(new SomeTestStruct_Auto(), IntPtr.Zero, fDeleteOld: true));
+        }
+
+        [Fact]
+        public void StructureToPtr_NullStructure_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.StructureToPtr(null, (IntPtr)1, fDeleteOld: true));
+            AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.StructureToPtr<object>(null, (IntPtr)1, fDeleteOld: true));
+        }
+
+        public static IEnumerable<object[]> StructureToPtr_GenericClass_TestData()
+        {
+            yield return new object[] { new GenericClass<string>() };
+            yield return new object[] { new GenericStruct<string>() };
+        }
+
+        [Theory]
+        [MemberData(nameof(StructureToPtr_GenericClass_TestData))]
+        public void StructureToPtr_GenericObject_ThrowsArgumentException(object o)
+        {
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.StructureToPtr(o, (IntPtr)1, fDeleteOld: true));
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.StructureToPtr<object>(o, (IntPtr)1, fDeleteOld: true));
+        }
+
+        public static IEnumerable<object[]> StructureToPtr_NonBlittableObject_TestData()
+        {
+            yield return new object[] { new NonGenericClass() };
+            yield return new object[] { "string" };
+        }
+
+        [Theory]
+        [MemberData(nameof(StructureToPtr_NonBlittableObject_TestData))]
+        public void StructureToPtr_NonBlittable_ThrowsArgumentException(object o)
         {
-            var structure1 = new StructWithDateArray()
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.StructureToPtr(o, (IntPtr)1, fDeleteOld: true));
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.StructureToPtr<object>(o, (IntPtr)1, fDeleteOld: true));
+        }
+
+        [Fact]
+        public void StructureToPtr_AutoLayout_ThrowsArgumentException()
+        {
+            var someTs_Auto = new SomeTestStruct_Auto();
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.StructureToPtr((object)someTs_Auto, (IntPtr)1, fDeleteOld: true));
+            AssertExtensions.Throws<ArgumentException>("structure", () => Marshal.StructureToPtr(someTs_Auto, (IntPtr)1, fDeleteOld: true));
+        }
+
+        [Fact]
+        public void StructureToPtr_InvalidLengthByValArrayInStruct_ThrowsArgumentException()
+        {
+            var structure = new StructWithByValArray
             {
-                array = new DateTime[]
+                array = new StructWithIntField[]
                 {
-                    DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now
+                    new StructWithIntField { value = 1 },
+                    new StructWithIntField { value = 2 },
+                    new StructWithIntField { value = 3 },
+                    new StructWithIntField { value = 4 }
                 }
             };
-
-            int size = Marshal.SizeOf(structure1);
+            int size = Marshal.SizeOf(structure);
             IntPtr memory = Marshal.AllocHGlobal(size);
             try
             {
-                Marshal.StructureToPtr(structure1, memory, false);
-                Marshal.StructureToPtr(structure1, memory, true);
+                Assert.Throws<ArgumentException>(() => Marshal.StructureToPtr(structure, memory, false));
+                Assert.Throws<ArgumentException>(() => Marshal.StructureToPtr(structure, memory, true));
             }
             finally
             {
                 Marshal.FreeHGlobal(memory);
             }
         }
+
+        public struct StructWithIntField
+        {
+            public int value;
+        }
+
+        public struct StructWithByValArray
+        {
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+            public StructWithIntField[] array;
+        }
+
+        public struct StructWithBoolArray
+        {
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+            public bool[] array;
+        }
+
+        public struct StructWithDateArray
+        {
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+            public DateTime[] array;
+        }
+
+        [StructLayout(LayoutKind.Auto)]
+        public struct SomeTestStruct_Auto
+        {
+            public int i;
+        }
     }
 }
index fcb8e6a..1188692 100644 (file)
@@ -9,26 +9,19 @@ namespace System.Runtime.InteropServices.Tests
     public class UnsafeAddrOfPinnedArrayElementTests
     {
         [Fact]
-        public void NullParameter()
+        public void UnsafeAddrOfPinnedArrayElement_NonGenericPrimitiveArray_ReturnsExpected()
         {
-            int[] array = null;
-            AssertExtensions.Throws<ArgumentNullException>("arr", () => Marshal.UnsafeAddrOfPinnedArrayElement<int>(array, 0));
-        }
-
-        [Fact]
-        public void PrimitiveType()
-        {
-            int[] array = new int[] { 1, 2, 3 };
+            Array array = new int[] { 1, 2, 3 };
             GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
             try
             {
-                IntPtr v0 = Marshal.UnsafeAddrOfPinnedArrayElement<int>(array, 0);
+                IntPtr v0 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
                 Assert.Equal(1, Marshal.ReadInt32(v0));
 
-                IntPtr v1 = Marshal.UnsafeAddrOfPinnedArrayElement<int>(array, 1);
+                IntPtr v1 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 1);
                 Assert.Equal(2, Marshal.ReadInt32(v1));
 
-                IntPtr v2 = Marshal.UnsafeAddrOfPinnedArrayElement<int>(array, 2);
+                IntPtr v2 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 2);
                 Assert.Equal(3, Marshal.ReadInt32(v2));
             }
             finally
@@ -37,36 +30,86 @@ namespace System.Runtime.InteropServices.Tests
             }
         }
 
+        [Fact]
+        public void UnsafeAddrOfPinnedArrayElement_NonGenericStructureArray_ReturnsExpected()
+        {
+            Array array = new Point[]
+            {
+                new Point() {x = 100, y = 100 },
+                new Point() {x = -1, y = -1 },
+                new Point() {x = 0, y = 0 }
+            };
+
+            GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+            try
+            {
+                IntPtr v0 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
+                Point p0 = Marshal.PtrToStructure<Point>(v0);
+                Assert.Equal(100, p0.x);
+                Assert.Equal(100, p0.y);
+
+                IntPtr v1 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 1);
+                Point p1 = Marshal.PtrToStructure<Point>(v1);
+                Assert.Equal(-1, p1.x);
+                Assert.Equal(-1, p1.y);
 
-        struct Point
+                IntPtr v2 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 2);
+                Point p2 = Marshal.PtrToStructure<Point>(v2);
+                Assert.Equal(0, p2.x);
+                Assert.Equal(0, p2.y);
+            }
+            finally
+            {
+                handle.Free();
+            }
+        }
+
+        [Fact]
+        public void UnsafeAddrOfPinnedArrayElement_GenericPrimitiveArray_ReturnsExpected()
         {
-            public int x;
-            public int y;
+            var array = new int[] { 1, 2, 3 };
+            GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+            try
+            {
+                IntPtr v0 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
+                Assert.Equal(1, Marshal.ReadInt32(v0));
+
+                IntPtr v1 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 1);
+                Assert.Equal(2, Marshal.ReadInt32(v1));
+
+                IntPtr v2 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 2);
+                Assert.Equal(3, Marshal.ReadInt32(v2));
+            }
+            finally
+            {
+                handle.Free();
+            }
         }
 
         [Fact]
-        public void StructType()
+        public void UnsafeAddrOfPinnedArrayElement_GenericStructureArray_ReturnsExpected()
         {
-            Point[] array = new Point[]{
-            new Point(){x = 100, y = 100},
-            new Point(){x = -1, y = -1},
-            new Point(){x = 0, y = 0},
+            var array = new Point[]
+            {
+                new Point() {x = 100, y = 100 },
+                new Point() {x = -1, y = -1 },
+                new Point() {x = 0, y = 0 }
             };
 
             GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
             try
             {
-                IntPtr v0 = Marshal.UnsafeAddrOfPinnedArrayElement<Point>(array, 0);
+                IntPtr v0 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
                 Point p0 = Marshal.PtrToStructure<Point>(v0);
                 Assert.Equal(100, p0.x);
                 Assert.Equal(100, p0.y);
 
-                IntPtr v1 = Marshal.UnsafeAddrOfPinnedArrayElement<Point>(array, 1);
+                IntPtr v1 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 1);
                 Point p1 = Marshal.PtrToStructure<Point>(v1);
                 Assert.Equal(-1, p1.x);
                 Assert.Equal(-1, p1.y);
 
-                IntPtr v2 = Marshal.UnsafeAddrOfPinnedArrayElement<Point>(array, 2);
+                IntPtr v2 = Marshal.UnsafeAddrOfPinnedArrayElement(array, 2);
                 Point p2 = Marshal.PtrToStructure<Point>(v2);
                 Assert.Equal(0, p2.x);
                 Assert.Equal(0, p2.y);
@@ -76,5 +119,18 @@ namespace System.Runtime.InteropServices.Tests
                 handle.Free();
             }
         }
+
+        [Fact]
+        public void UnsafeAddrOfPinnedArrayElement_NullArray_ThrowsArgumentNullException()
+        {
+            AssertExtensions.Throws<ArgumentNullException>("arr", () => Marshal.UnsafeAddrOfPinnedArrayElement(null, 0));
+            AssertExtensions.Throws<ArgumentNullException>("arr", () => Marshal.UnsafeAddrOfPinnedArrayElement((int[])null, 0));
+        }
+
+        public struct Point
+        {
+            public int x;
+            public int y;
+        }
     }
 }