Add tests for our layout-class marshalling (#20867)
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>
Wed, 9 Jan 2019 23:03:43 +0000 (15:03 -0800)
committerGitHub <noreply@github.com>
Wed, 9 Jan 2019 23:03:43 +0000 (15:03 -0800)
* Add simple test for the LayoutClassMarshaler (most of the code is already covered by the struct marshalling tests).

* Add test for blittable layout class.

* Apparently layout classes are passed by value when passed as struct fields instead of byref.

tests/src/Interop/CMakeLists.txt
tests/src/Interop/LayoutClass/CMakeLists.txt [new file with mode: 0644]
tests/src/Interop/LayoutClass/LayoutClassNative.cpp [new file with mode: 0644]
tests/src/Interop/LayoutClass/LayoutClassTest.cs [new file with mode: 0644]
tests/src/Interop/LayoutClass/LayoutClassTest.csproj [new file with mode: 0644]

index 9e0bf85..9784ea1 100644 (file)
@@ -61,6 +61,7 @@ add_subdirectory(DllImportAttribute/ExeFile)
 add_subdirectory(DllImportAttribute/FileNameContainDot)
 add_subdirectory(DllImportAttribute/Simple)
 add_subdirectory(ExecInDefAppDom)
+add_subdirectory(LayoutClass)
 
 if(WIN32)
     add_subdirectory(PInvoke/Attributes/LCID)
diff --git a/tests/src/Interop/LayoutClass/CMakeLists.txt b/tests/src/Interop/LayoutClass/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5626d66
--- /dev/null
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.6)
+project (LayoutClassNative)
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES LayoutClassNative.cpp )
+
+# add the executable
+add_library (LayoutClassNative SHARED ${SOURCES})
+target_link_libraries(LayoutClassNative ${LINK_LIBRARIES_ADDITIONAL}) 
+
+# add the install targets
+install (TARGETS LayoutClassNative DESTINATION bin)
diff --git a/tests/src/Interop/LayoutClass/LayoutClassNative.cpp b/tests/src/Interop/LayoutClass/LayoutClassNative.cpp
new file mode 100644 (file)
index 0000000..3185040
--- /dev/null
@@ -0,0 +1,74 @@
+#include "platformdefines.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <xplatform.h>
+
+typedef void *voidPtr;
+struct SeqClass
+{
+    int a; 
+    bool b;
+    char* str;
+};
+
+struct ExpClass
+{ 
+       int a;
+       int extra; //padding needs to be added here as we have added 8 byte offset.
+       union
+       {
+               int i;
+               BOOL b;
+               double d;
+       } udata;
+};
+
+struct BlittableClass
+{
+    int a;
+};
+
+struct NestedLayoutClass
+{
+    SeqClass str;
+};
+
+extern "C"
+DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleSeqLayoutClassByRef(SeqClass *p) 
+{
+    if((p->a != 0) || (p->b) || strcmp(p->str, "before") != 0)
+    {
+        printf("\np->a=%d, p->b=%s, p->str=%s", p->a, p->b ? "true" : "false", p->str);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+extern "C"
+DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleBlittableSeqLayoutClassByRef(BlittableClass *p) 
+{
+    if(p->a != 10)
+    {
+        printf("\np->a=%d", p->a);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+extern "C"
+DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleExpLayoutClassByRef(ExpClass *p)
+{
+       if((p->a != 0) || (p->udata.i != 10))
+       {
+               printf("\np->a=%d, p->udata.i=%d\n",p->a,p->udata.i);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleNestedLayoutClassByValue(NestedLayoutClass v)
+{
+    return SimpleSeqLayoutClassByRef(&v.str);
+}
diff --git a/tests/src/Interop/LayoutClass/LayoutClassTest.cs b/tests/src/Interop/LayoutClass/LayoutClassTest.cs
new file mode 100644 (file)
index 0000000..49984d5
--- /dev/null
@@ -0,0 +1,227 @@
+using System;
+using System.Security;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using TestLibrary;
+
+namespace PInvokeTests
+{
+    [StructLayout(LayoutKind.Sequential)]
+    public class SeqClass
+    {
+        public int a;
+        public bool b;
+        public string str;
+
+        public SeqClass(int _a, bool _b, string _str)
+        {
+            a = _a;
+            b = _b;
+            str = String.Concat(_str, "");
+        }
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    public class ExpClass
+    {
+        [FieldOffset(0)]
+        public DialogResult type;
+
+        [FieldOffset(8)]
+        public int i;
+
+        [FieldOffset(8)]
+        public bool b;
+
+        [FieldOffset(8)]
+        public double c;
+
+        public ExpClass(DialogResult t, int num)
+        {
+            type = t;
+            b = false;
+            c = num;
+            i = num;
+        }
+        public ExpClass(DialogResult t, double dnum)
+        {
+            type = t;
+            b = false;
+            i = 0;
+            c = dnum;
+        }
+        public ExpClass(DialogResult t, bool bnum)
+        {
+            type = t;
+            i = 0;
+            c = 0;
+            b = bnum;
+        }
+     }
+
+    public enum DialogResult
+    {
+        None = 0,
+        OK = 1,
+        Cancel = 2
+    }
+
+    
+    [StructLayout(LayoutKind.Sequential)]
+    public class Blittable
+    {
+        public int a;
+
+        public Blittable(int _a)
+        {
+            a = _a;
+        }
+    }
+
+    public struct NestedLayout
+    {
+        public SeqClass value;
+    }
+
+    class StructureTests
+    {
+        [DllImport("LayoutClassNative")]
+        private static extern bool SimpleSeqLayoutClassByRef(SeqClass p);
+
+        [DllImport("LayoutClassNative")]
+        private static extern bool SimpleExpLayoutClassByRef(ExpClass p);
+
+        [DllImport("LayoutClassNative")]
+        private static extern bool SimpleNestedLayoutClassByValue(NestedLayout p);
+
+        [DllImport("LayoutClassNative")]
+        private static extern bool SimpleBlittableSeqLayoutClassByRef(Blittable p);
+
+        public static bool SequentialClass()
+        {
+            string s = "before";
+            bool retval = true;
+            SeqClass p = new SeqClass(0, false, s);
+
+            TestFramework.BeginScenario("Test #1 Pass a sequential layout class.");
+
+            try
+            {
+                retval = SimpleSeqLayoutClassByRef(p);
+
+                if (retval == false)
+                {
+                    TestFramework.LogError("01", "PInvokeTests->SequentialClass : Unexpected error occured on unmanaged side");
+                    return false;
+                }
+            }
+            catch (Exception e)
+            {
+                TestFramework.LogError("04", "Unexpected exception: " + e.ToString());
+                retval = false;
+            }
+
+            return retval;
+        }
+
+        public static bool ExplicitClass()
+        {
+            ExpClass p;
+            bool retval = false;
+
+            TestFramework.BeginScenario("Test #2 Pass an explicit layout class.");
+
+            try
+            {
+                p = new ExpClass(DialogResult.None, 10);
+                retval = SimpleExpLayoutClassByRef(p);
+
+                if (retval == false)
+                {
+                    TestFramework.LogError("01", "PInvokeTests->ExplicitClass : Unexpected error occured on unmanaged side");
+                    return false;
+                }
+
+            }
+            catch (Exception e)
+            {
+                TestFramework.LogError("03", "Unexpected exception: " + e.ToString());
+                retval = false;
+            }
+
+            return retval;
+        }
+
+        public static bool BlittableClass()
+        {
+            bool retval = true;
+            Blittable p = new Blittable(10);
+
+            TestFramework.BeginScenario("Test #3 Pass a blittable sequential layout class.");
+
+            try
+            {
+                retval = SimpleBlittableSeqLayoutClassByRef(p);
+
+                if (retval == false)
+                {
+                    TestFramework.LogError("01", "PInvokeTests->Blittable : Unexpected error occured on unmanaged side");
+                    return false;
+                }
+            }
+            catch (Exception e)
+            {
+                TestFramework.LogError("04", "Unexpected exception: " + e.ToString());
+                retval = false;
+            }
+
+            return retval;
+        }
+        
+        public static bool NestedLayoutClass()
+        {
+            string s = "before";
+            bool retval = true;
+            SeqClass p = new SeqClass(0, false, s);
+            NestedLayout target = new NestedLayout
+            {
+                value = p
+            };
+
+            TestFramework.BeginScenario("Test #4 Nested sequential layout class in a structure.");
+
+            try
+            {
+                retval = SimpleNestedLayoutClassByValue(target);
+
+                if (retval == false)
+                {
+                    TestFramework.LogError("01", "PInvokeTests->NestedLayoutClass : Unexpected error occured on unmanaged side");
+                    return false;
+                }
+            }
+            catch (Exception e)
+            {
+                TestFramework.LogError("04", "Unexpected exception: " + e.ToString());
+                retval = false;
+            }
+
+            return retval;
+        }
+
+        public static int Main(string[] argv)
+        {
+            bool retVal = true;
+
+            retVal = retVal && SequentialClass();
+            retVal = retVal && ExplicitClass();
+            retVal = retVal && BlittableClass();
+            retVal = retVal && NestedLayoutClass();
+
+            return (retVal ? 100 : 101);
+        }
+
+
+    }
+}
diff --git a/tests/src/Interop/LayoutClass/LayoutClassTest.csproj b/tests/src/Interop/LayoutClass/LayoutClassTest.csproj
new file mode 100644 (file)
index 0000000..caf67cf
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>LayoutClassTest</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+    <OutputType>exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"></PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"></PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="*.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+      <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+      <Name>CoreCLRTestLibrary</Name>
+    </ProjectReference>
+    <ProjectReference Include="CMakeLists.txt"></ProjectReference>
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>