Add PInvoke/DllImportpath tests (#19270)
authorZeng Jiang <v-jiazen@microsoft.com>
Thu, 15 Nov 2018 22:51:02 +0000 (06:51 +0800)
committerJeremy Koritzinsky <jkoritzinsky@gmail.com>
Thu, 15 Nov 2018 22:51:02 +0000 (14:51 -0800)
* Add PInvoke/DllImportpath tests

* Refactor test to current toolset and remove Windows-only Path API searching.

* Remove explicit calling convention from managed and add correct convention to test.

* Get environment test passing on Unix.

* Update test to pass off-Windows.

* Include feature/platform defines in tests.

* Fix environment test (again).

* Remove zero-width character that's breaking CI

* Fix zero-width character I missed.

* Remove invalid parens around LD_LIBRARY_PATH

* Ensure the path added to the LD_LIBRARY_PATH exists before the test starts.

* Combine all DllImportPath CMakeLists.txt files into one file.

* Include clr.coreclr.props when also including clr.defines.targets so we get the feature defines correctly as well.

* Disable unicode test for our OSX 10.12 CI builds.

tests/src/Interop/CMakeLists.txt
tests/src/Interop/PInvoke/DllImportPath/CMakeLists.txt [new file with mode: 0644]
tests/src/Interop/PInvoke/DllImportPath/DllImportPathNative.cpp [new file with mode: 0644]
tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.cs [new file with mode: 0644]
tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.csproj [new file with mode: 0644]
tests/src/dir.targets

index cab63b7..9825873 100644 (file)
@@ -12,6 +12,7 @@ list(APPEND LINK_LIBRARIES_ADDITIONAL platformdefines)
 SET(CLR_INTEROP_TEST_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
 
 include_directories(common)
+add_subdirectory(PInvoke/DllImportPath)
 add_subdirectory(PInvoke/BestFitMapping/Char)
 add_subdirectory(PInvoke/BestFitMapping/LPStr)
 add_subdirectory(PInvoke/Delegate/MarshalDelegateAsField)
diff --git a/tests/src/Interop/PInvoke/DllImportPath/CMakeLists.txt b/tests/src/Interop/PInvoke/DllImportPath/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a0d2992
--- /dev/null
@@ -0,0 +1,25 @@
+cmake_minimum_required (VERSION 2.6) 
+project (DllImportPath) 
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") 
+include_directories(${INC_PLATFORM_DIR}) 
+set(SOURCES 
+    DllImportPathNative.cpp 
+) 
+# Additional files to reference: 
+# add the executable 
+add_library (DllImportPath_Local SHARED ${SOURCES})
+add_library (DllImportPath.Local SHARED ${SOURCES})
+add_library (DllImportPath_PathEnv SHARED ${SOURCES})
+add_library (DllImportPath_Relative SHARED ${SOURCES})
+add_library (DllImportPath_U�n�i�c�o�d�e SHARED ${SOURCES}) 
+target_link_libraries(DllImportPath_Local ${LINK_LIBRARIES_ADDITIONAL}) 
+target_link_libraries(DllImportPath.Local ${LINK_LIBRARIES_ADDITIONAL}) 
+target_link_libraries(DllImportPath_PathEnv ${LINK_LIBRARIES_ADDITIONAL}) 
+target_link_libraries(DllImportPath_Relative ${LINK_LIBRARIES_ADDITIONAL}) 
+target_link_libraries(DllImportPath_U�n�i�c�o�d�e ${LINK_LIBRARIES_ADDITIONAL}) 
+# add the install targets 
+install (TARGETS DllImportPath_Local DESTINATION bin) 
+install (TARGETS DllImportPath.Local DESTINATION bin) 
+install (TARGETS DllImportPath_PathEnv DESTINATION bin) 
+install (TARGETS DllImportPath_Relative DESTINATION bin) 
+install (TARGETS DllImportPath_U�n�i�c�o�d�e DESTINATION bin) 
diff --git a/tests/src/Interop/PInvoke/DllImportPath/DllImportPathNative.cpp b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathNative.cpp
new file mode 100644 (file)
index 0000000..e3ad7cd
--- /dev/null
@@ -0,0 +1,46 @@
+// 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.
+
+#include <stdio.h>
+#include <xplatform.h>
+
+LPCWSTR strManaged = W("Managed\0String\0");
+LPCWSTR strNative = W(" Native\0String\0");
+
+size_t lenstrManaged = 7; // the length of strManaged
+size_t lenstrNative = 7; //the len of strNative
+
+extern "C" DLL_EXPORT bool STDMETHODCALLTYPE MarshalStringPointer_InOut(/*[in,out]*/LPWSTR *s)
+{
+    //Check the Input
+    size_t len = wcslen(*s);
+    if((len != lenstrManaged)||(wcsncmp(*s,strManaged, lenstrManaged)!=0))
+    {
+        printf("Error in Function MarshalStringPointer_InOut\n");
+
+        //Expected
+        printf("Expected:");
+        wprintf(L"%ls",strManaged);
+        printf("\tThe length of Expected:%d\n",static_cast<int>(lenstrManaged));
+
+        //Actual
+        printf("Actual:");
+        wprintf(L"%ls",*s);
+        printf("\tThe length of Actual:%d\n",static_cast<int>(len));
+
+        return false;
+    }
+
+    //Allocate New
+    CoreClrFree(*s);
+
+    //Alloc New
+    size_t length = lenstrNative + 1;
+    *s = (LPWSTR)CoreClrAlloc(length * sizeof(WCHAR));
+    memset(*s,'\0',length * sizeof(WCHAR));
+    wcsncpy_s(*s,length,strNative,lenstrNative);
+
+    //Return
+    return true;
+}
diff --git a/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.cs b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.cs
new file mode 100644 (file)
index 0000000..03c7cbc
--- /dev/null
@@ -0,0 +1,272 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+class Test
+{
+    private const string RelativeSubdirectoryName = "RelativeNative";
+    private const string PathEnvSubdirectoryName = "Subdirectory";
+    private const string PathEnvFileName = "MovedNativeLib";
+
+#if PLATFORM_WINDOWS
+    private const string RelativePath1 = @".\RelativeNative\..\DllImportPath_Relative";
+    private const string RelativePath3 = @"..\DllImportPathTest\DllImportPath_Relative";
+#else
+    private const string RelativePath1 =  @"./RelativeNative/../libDllImportPath_Relative";
+    private const string RelativePath3 = @"../DllImportPathTest/libDllImportPath_Relative";
+#endif
+
+    [DllImport(@"DllImportPath_Local", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_Local1([In, Out]ref string strManaged);
+
+    [DllImport(@".\DllImportPath_Local", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_Local2([In, Out]ref string strManaged);
+
+    [DllImport(@"DllImportPath.Local.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_LocalWithDot1([In, Out]ref string strManaged);
+
+    [DllImport(@".\DllImportPath.Local.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_LocalWithDot2([In, Out]ref string strManaged);
+
+    [DllImport(RelativePath1, CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_Relative1([In, Out]ref string strManaged);
+
+    [DllImport(@"..\DllImportPathTest\DllImportPath_Relative.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_Relative2([In, Out]ref string strManaged);
+
+    [DllImport(RelativePath3, CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_Relative3([In, Out]ref string strManaged);
+
+    [DllImport(@".\..\DllImportPathTest\DllImportPath_Relative.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_Relative4([In, Out]ref string strManaged);
+
+    [DllImport(@"DllImportPath_U�n�i�c�o�d�e", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_Unicode([In, Out]ref string strManaged);
+    
+    [DllImport(PathEnvFileName, CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")]
+    private static extern bool MarshalStringPointer_InOut_PathEnv([In, Out]ref string strManaged);
+
+    static bool DllExistsOnLocalPath()
+    {
+        string strManaged = "Managed";
+        string native = " Native";
+
+        Console.WriteLine("[Calling MarshalStringPointer_InOut_Local1].");
+        string strPara1 = strManaged;
+        if (!MarshalStringPointer_InOut_Local1(ref strPara1))
+        {
+            Console.WriteLine("Return value is wrong");
+            return false;
+        }
+
+        if (native != strPara1)
+        {
+            Console.WriteLine("The passed string is wrong");
+            return false;
+        }
+
+        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+        {
+            Console.WriteLine("[Calling MarshalStringPointer_InOut_Local2]");
+            string strPara2 = strManaged;
+            if (!MarshalStringPointer_InOut_Local2(ref strPara2))
+            {
+                Console.WriteLine("Return value is wrong");
+                return false;
+            }
+
+            if (native != strPara2)
+            {
+                Console.WriteLine("The passed string is wrong");
+                return false;
+            }
+
+            Console.WriteLine("[Calling MarshalStringPointer_InOut_LocalWithDot1]");
+            string strPara3 = strManaged;
+            if (!MarshalStringPointer_InOut_LocalWithDot1(ref strPara3))
+            {
+                Console.WriteLine("Return value is wrong");
+                return false;
+            }
+
+            if (native != strPara3)
+            {
+                Console.WriteLine("The passed string is wrong");
+                return false;
+            }
+
+            Console.WriteLine("[Calling MarshalStringPointer_InOut_LocalWithDot2]");
+            string strPara4 = strManaged;
+            if (!MarshalStringPointer_InOut_LocalWithDot2(ref strPara4))
+            {
+                Console.WriteLine("Return value is wrong");
+                return false;
+            }
+
+            if (native != strPara4)
+            {
+                Console.WriteLine("The passed string is wrong");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    static bool DllExistsOnRelativePath()
+    {
+        string strManaged = "Managed";
+        string native = " Native";
+
+        if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // We need to ensure that the subdirectory exists for off-Windows.
+        {        
+            var currentDirectory = Directory.GetCurrentDirectory();
+            var info = new DirectoryInfo(currentDirectory);
+            info.CreateSubdirectory(RelativeSubdirectoryName);
+        }
+
+        Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative1]");
+        string strPara5 = strManaged;
+        if (!MarshalStringPointer_InOut_Relative1(ref strPara5))
+        {
+            Console.WriteLine("Return value is wrong");
+            return false;
+        }
+
+        if (native != strPara5)
+        {
+            Console.WriteLine("The passed string is wrong");
+            return false;
+        }
+        
+        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+        {
+            Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative2]");
+            string strPara6 = strManaged;
+            if (!MarshalStringPointer_InOut_Relative2(ref strPara6))
+            {
+                Console.WriteLine("Return value is wrong");
+                return false;
+            }
+
+            if (native != strPara6)
+            {
+                Console.WriteLine("The passed string is wrong");
+                return false;
+            }
+        }
+        
+        Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative3]");
+        string strPara7 = strManaged;
+        if (!MarshalStringPointer_InOut_Relative3(ref strPara7))
+        {
+            Console.WriteLine("Return value is wrong");
+            return false;
+        }
+
+        if (native != strPara7)
+        {
+            Console.WriteLine("The passed string is wrong");
+            return false;
+        }
+
+        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+        {
+            Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative4]");
+            string strPara8 = strManaged;
+            if (!MarshalStringPointer_InOut_Relative4(ref strPara8))
+            {
+                Console.WriteLine("Return value is wrong");
+                return false;
+            }
+        
+            if (native != strPara8)
+            {
+                Console.WriteLine("The passed string is wrong");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static void SetupPathEnvTest()
+    {
+        var currentDirectory = Directory.GetCurrentDirectory();
+        var info = new DirectoryInfo(currentDirectory);
+        var subDirectory = info.CreateSubdirectory(PathEnvSubdirectoryName);
+
+        var file = info.EnumerateFiles("*DllImportPath_PathEnv*", SearchOption.TopDirectoryOnly).FirstOrDefault();
+
+        var newFileLocation = Path.Combine(subDirectory.FullName, file.Name);
+
+        file.CopyTo(Path.Combine(subDirectory.FullName, PathEnvFileName + file.Extension), true);
+
+        Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + $";{subDirectory.FullName}");
+    }
+
+    static bool DllExistsOnPathEnv()
+    {
+        SetupPathEnvTest();
+
+        string managed = "Managed";
+        string native = " Native";
+
+        Console.WriteLine("[Calling MarshalStringPointer_InOut_PathEnv]");
+        if (!MarshalStringPointer_InOut_PathEnv(ref managed))
+        {
+            Console.WriteLine("Return value is wrong");
+            return false;
+        }
+
+        if (native != managed)
+        {
+            Console.WriteLine($"The passed string is wrong. Expected {native} got {managed}.");
+            return false;
+        }
+
+        return true;
+    }
+
+    static bool DllExistsUnicode()
+    {
+        string managed = "Managed";
+        string native = " Native";
+        
+        Console.WriteLine("[Calling MarshalStringPointer_InOut_Unicode]");
+        if (!MarshalStringPointer_InOut_Unicode(ref managed))
+        {
+            Console.WriteLine("Return value is wrong");
+            return false;
+        }
+
+        if (native != managed)
+        {
+            Console.WriteLine("The passed string is wrong");
+            return false;
+        }
+
+        return true;
+    }
+
+    public static int Main(string[] args)
+    {
+        bool success = true;
+
+        success = success && DllExistsOnLocalPath();
+        success = success && DllExistsOnRelativePath();
+
+        if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) // This test fails due to a bug in OSX 10.12 combined with the weird way that HFS+ handles unicode file names
+        {
+            success = success && DllExistsUnicode();
+        }
+        success = success && DllExistsOnPathEnv();
+        
+        return success ? 100 : 101;
+    }
+}
diff --git a/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.csproj b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.csproj
new file mode 100644 (file)
index 0000000..57e08f1
--- /dev/null
@@ -0,0 +1,41 @@
+<?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>DllImportPathTest</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>
+    <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="DllImportPathTest.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <CLRTestBashEnvironmentVariable Include="export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$%28pwd)/Subdirectory" />
+  </ItemGroup>
+  <PropertyGroup>
+    <PathEnvSetupCommands>
+    <![CDATA[
+      mkdir Subdirectory
+      ]]>
+    </PathEnvSetupCommands>
+    <BashCLRTestPreCommands>$(BashCLRTestPreCommands);$(PathEnvSetupCommands)</BashCLRTestPreCommands>
+  </PropertyGroup>
+  <ItemGroup>
+    <ProjectReference Include="CMakeLists.txt" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
index 3e3ce9b..ac803ee 100644 (file)
     <ProjectAssetsFile></ProjectAssetsFile>
   </PropertyGroup>
 
+  <Import Project="../../clr.coreclr.props" />
+  <Import Project="../../clr.defines.targets" />
+
 </Project>