Merge pull request #3528 from BrzVlad/fix-sgen-check-before-collections
[mono.git] / mcs / class / corlib / Test / System.Runtime.InteropServices / MarshalTest.cs
index d6f2a49bf38d774f3ee0f8be8c7a3f1f2f37c685..d4ca72dc0a94857730af44a9635cffa80624a605 100644 (file)
@@ -28,7 +28,7 @@ namespace MonoTests.System.Runtime.InteropServices
                        public int field;
                }
 
-               class ClsNoLayout {
+               public class ClsNoLayout {
                        public int field;
                }
 
@@ -173,12 +173,20 @@ namespace MonoTests.System.Runtime.InteropServices
                        Marshal.FreeHGlobal (ptr);
                }
 
-               struct Foo {
-                       int a;
-                       static int b;
-                       long c;
-                       static char d;
-                       int e;
+               [Test]
+               public void AllocCoTaskMemZeroSize ()
+               {
+                       IntPtr ptr = Marshal.AllocCoTaskMem (0);
+                       Assert.IsTrue (ptr != IntPtr.Zero);
+                       Marshal.FreeCoTaskMem (ptr);
+               }
+
+               public struct Foo {
+                       public int a;
+                       public static int b;
+                       public long c;
+                       public static char d;
+                       public int e;
                }
 
                [Test]
@@ -200,8 +208,8 @@ namespace MonoTests.System.Runtime.InteropServices
                [Test]
                public void GetHINSTANCE ()
                {
-                       if (RunningOnUnix)
-                               Assert.Ignore ("GetHINSTANCE only applies to Windows.");
+                       if (RunningOnMono)
+                               Assert.Ignore ("GetHINSTANCE only applies to .NET on Windows.");
 
                        Assembly a;
                        IntPtr hinstance;
@@ -252,6 +260,15 @@ namespace MonoTests.System.Runtime.InteropServices
                        }
                }
 #endif
+
+               [Test]
+               public void GetHRForException ()
+               {
+                       Assert.AreEqual (0, Marshal.GetHRForException (null));
+                       Assert.IsTrue (Marshal.GetHRForException (new Exception ()) < 0);
+                       Assert.AreEqual (12345, Marshal.GetHRForException (new IOException ("test message", 12345)));
+               }
+
                [Test] // bug #319009
                public void StringToHGlobalUni ()
                {
@@ -290,9 +307,7 @@ namespace MonoTests.System.Runtime.InteropServices
                                Assert.AreEqual (0x1234, Marshal.ReadInt16 (ptr));
                                Assert.AreEqual (0x1234, Marshal.ReadInt16 (ptr, 0));
                                Assert.AreEqual (0x4567, Marshal.ReadInt16 (ptr, 2));
-#if NET_4_5
                                Assert.AreEqual (0x4567, Marshal.ReadInt16 ((ptr + 5)));
-#endif
                                Assert.AreEqual (0x4567, Marshal.ReadInt16 (ptr, 5));
                        } finally {
                                Marshal.FreeHGlobal (ptr);
@@ -310,9 +325,7 @@ namespace MonoTests.System.Runtime.InteropServices
                                Assert.AreEqual (0x12345678, Marshal.ReadInt32 (ptr));
                                Assert.AreEqual (0x12345678, Marshal.ReadInt32 (ptr, 0));
                                Assert.AreEqual (0x77654321, Marshal.ReadInt32 (ptr, 4));
-#if NET_4_5
                                Assert.AreEqual (0x77654321, Marshal.ReadInt32 ((ptr + 10)));
-#endif
                                Assert.AreEqual (0x77654321, Marshal.ReadInt32 (ptr, 10));
                        } finally {
                                Marshal.FreeHGlobal (ptr);
@@ -497,7 +510,6 @@ namespace MonoTests.System.Runtime.InteropServices
                                Marshal.FreeCoTaskMem (ptr);
                        }
                }
-#if NET_2_0
                private const string NotSupported = "Not supported before Windows 2000 Service Pack 3";
                private static char[] PlainText = new char[] { 'a', 'b', 'c' };
                private static byte[] AsciiPlainText = new byte[] { (byte) 'a', (byte) 'b', (byte) 'c' };
@@ -663,9 +675,8 @@ namespace MonoTests.System.Runtime.InteropServices
                                Assert.Ignore (NotSupported);
                        }
                }
-#endif
 
-#if !NET_2_1
+#if !MOBILE
                [Test]
                public void TestGetComSlotForMethodInfo ()
                {
@@ -780,7 +791,6 @@ namespace MonoTests.System.Runtime.InteropServices
                        Assert.IsNull (Marshal.PtrToStructure (IntPtr.Zero, typeof (SimpleStruct2)));
                }
                
-#if NET_2_0
                [Test]
                public void TestGetExceptionForHR ()
                {
@@ -793,14 +803,13 @@ namespace MonoTests.System.Runtime.InteropServices
                        ex = Marshal.GetExceptionForHR (E_INVALIDARG);
                        Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "E_INVALIDARG");
                }
-#endif
-               bool RunningOnUnix {
+               bool RunningOnMono {
                        get {
-                               int p = (int) Environment.OSVersion.Platform;
-                               return ((p == 4) || (p == 128) || (p == 6));
+                               return (Type.GetType ("System.MonoType", false) != null);
                        }
                }
 
+#if !MOBILE
                [DllImport ("kernel32.dll", SetLastError = true)]
                [PreserveSig]
                static extern uint GetModuleFileName (
@@ -812,8 +821,154 @@ namespace MonoTests.System.Runtime.InteropServices
                        [MarshalAs (UnmanagedType.U4)]
                        int nSize
                );
+#endif
+
+               [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+               public class FourByteStruct
+               {
+                       public UInt16 value1;
+                       public UInt16 value2;
+               }
+
+               [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+               public class ByteArrayFourByteStruct : FourByteStruct
+               {
+                       [MarshalAs( UnmanagedType.ByValArray, SizeConst = 5 )]
+                       public byte[] array;
+               }
+
+               [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+               public class SingleByteStruct
+               {
+                       public byte value1;
+               }
+
+               [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+               public class ByteArraySingleByteStruct : SingleByteStruct
+               {
+                       [MarshalAs( UnmanagedType.ByValArray, SizeConst = 5 )]
+                       public byte[] array1;
+                       public byte value2;
+               }
+
+               [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+               public class ByteArraySingleByteChildStruct : ByteArraySingleByteStruct
+               {
+                       [MarshalAs( UnmanagedType.ByValArray, SizeConst = 5 )]
+                       public byte[] array2;
+               }
+
+               [Test]
+               public void CheckByteArrayFourByteStruct()
+               {
+                       ByteArrayFourByteStruct myStruct = new ByteArrayFourByteStruct
+                       { value1 = 42, value2 = 53, array = Encoding.UTF8.GetBytes( "Hello" ) };
+
+                       byte[] buffer = Serialize (myStruct);
+
+                       UInt16 value1 = BitConverter.ToUInt16 (buffer, 0);
+                       UInt16 value2 = BitConverter.ToUInt16 (buffer, 2);
+                       string array = Encoding.UTF8.GetString (buffer, 4, 5);
+
+                       Assert.AreEqual((UInt16)42, value1);
+                       Assert.AreEqual((UInt16)53, value2);
+                       Assert.AreEqual ("Hello", array);
+               }
+
+               [Test]
+               public void CheckByteArraySingleByteChildStruct()
+               {
+                       ByteArraySingleByteChildStruct myStruct = new ByteArraySingleByteChildStruct
+                       { value1 = 42, array1 = Encoding.UTF8.GetBytes( "Hello" ), value2 = 53,  array2 = Encoding.UTF8.GetBytes( "World" ) };
+
+                       byte[] array = Serialize (myStruct);
+
+                       byte value1 = array [0];
+                       string array1 = Encoding.UTF8.GetString (array, 1, 5);
+                       byte value2 = array [6];
+                       string array2 = Encoding.UTF8.GetString (array, 7, 5);
+
+                       Assert.AreEqual((byte)42, value1);
+                       Assert.AreEqual ("Hello", array1);
+                       Assert.AreEqual((byte)53, value2);
+                       Assert.AreEqual ("World", array2);
+               }
+
+               [StructLayout(LayoutKind.Sequential, Pack = 1)]
+               public struct FiveByteStruct
+               {
+                       public uint uIntField;
+                       public byte byteField;
+               };
+
+               [StructLayout(LayoutKind.Sequential, Pack = 1)]
+               public class Base
+               {
+                       public ushort firstUShortField;
+                       public ushort secondUShortField;
+               }
+
+               [StructLayout(LayoutKind.Sequential, Pack = 1)]
+               public class Derived : Base
+               {
+                       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
+                       public FiveByteStruct[] arrayField;
+               }
+
+               [Test]
+               public void CheckPtrToStructureWithFixedArrayAndBaseClassFields()
+               {
+                       const int arraySize = 6;
+                       var derived = new Derived
+                       {
+                               arrayField = new FiveByteStruct[arraySize],
+                               firstUShortField = 42,
+                               secondUShortField = 43
+                       };
+
+                       for (var i = 0; i < arraySize; ++i)
+                       {
+                               derived.arrayField[i].byteField = (byte)i;
+                               derived.arrayField[i].uIntField = (uint)i * 10;
+                       }
+
+                       var array = Serialize(derived);
+                       var deserializedDerived = Deserialize<Derived>(array);
+
+                       Assert.AreEqual(derived.firstUShortField, deserializedDerived.firstUShortField, "The firstUShortField differs, which is not expected.");
+                       Assert.AreEqual(derived.secondUShortField, deserializedDerived.secondUShortField, "The secondUShortField differs, which is not expected.");
+
+                       for (var i = 0; i < arraySize; ++i)
+                       {
+                               Assert.AreEqual(derived.arrayField[i].byteField, deserializedDerived.arrayField[i].byteField, string.Format("The byteField at index {0} differs, which is not expected.", i));
+                               Assert.AreEqual(derived.arrayField[i].uIntField, deserializedDerived.arrayField[i].uIntField, string.Format("The uIntField at index {0} differs, which is not expected.", i));
+                       }
+               }
+
+               public static byte[] Serialize( object obj )
+               {
+                       int nTypeSize = Marshal.SizeOf( obj );
+                       byte[] arrBuffer = new byte[nTypeSize];
+
+                       GCHandle hGCHandle = GCHandle.Alloc( arrBuffer, GCHandleType.Pinned );
+                       IntPtr pBuffer = hGCHandle.AddrOfPinnedObject();
+                       Marshal.StructureToPtr( obj, pBuffer, false );
+                       hGCHandle.Free();
+
+                       return arrBuffer;
+               }
+
+               public static T Deserialize<T>(byte[] buffer)
+               {
+                       var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+                       var pBuffer = handle.AddrOfPinnedObject();
+                       var objResult = (T)Marshal.PtrToStructure(pBuffer, typeof(T));
+                       handle.Free();
+
+                       return objResult;
+               }
        }
-#if !NET_2_1
+#if !MOBILE
        [ComImport()]
        [Guid("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA")]
        interface ITestDefault