summaryrefslogtreecommitdiff
path: root/tests/src
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src')
-rw-r--r--tests/src/Interop/CMakeLists.txt1
-rw-r--r--tests/src/Interop/StringMarshalling/UTF8/CMakeLists.txt9
-rw-r--r--tests/src/Interop/StringMarshalling/UTF8/UTF8Test.cs221
-rw-r--r--tests/src/Interop/StringMarshalling/UTF8/UTF8Test.csproj50
-rw-r--r--tests/src/Interop/StringMarshalling/UTF8/UTF8TestNative.cpp314
-rw-r--r--tests/src/Interop/StringMarshalling/UTF8/project.json15
6 files changed, 610 insertions, 0 deletions
diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt
index af51c5e665..370b699391 100644
--- a/tests/src/Interop/CMakeLists.txt
+++ b/tests/src/Interop/CMakeLists.txt
@@ -14,5 +14,6 @@ add_subdirectory(RefInt)
add_subdirectory(RefCharArray)
add_subdirectory(StringMarshalling/LPSTR)
add_subdirectory(StringMarshalling/LPTSTR)
+add_subdirectory(StringMarshalling/UTF8)
add_subdirectory(MarshalAPI/FunctionPointer)
add_subdirectory(MarshalAPI/IUnknown)
diff --git a/tests/src/Interop/StringMarshalling/UTF8/CMakeLists.txt b/tests/src/Interop/StringMarshalling/UTF8/CMakeLists.txt
new file mode 100644
index 0000000000..1e8edbf563
--- /dev/null
+++ b/tests/src/Interop/StringMarshalling/UTF8/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required (VERSION 2.6)
+project (UTF8TestNative)
+set(SOURCES UTF8TestNative.cpp )
+
+# add the executable
+add_library (UTF8TestNative SHARED ${SOURCES})
+
+# add the install targets
+install (TARGETS UTF8TestNative DESTINATION bin) \ No newline at end of file
diff --git a/tests/src/Interop/StringMarshalling/UTF8/UTF8Test.cs b/tests/src/Interop/StringMarshalling/UTF8/UTF8Test.cs
new file mode 100644
index 0000000000..7bfe19fdac
--- /dev/null
+++ b/tests/src/Interop/StringMarshalling/UTF8/UTF8Test.cs
@@ -0,0 +1,221 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Collections.Generic;
+
+
+// UTF8
+class UTF8StringTests
+{
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.LPUTF8Str)]
+ public static extern string StringParameterInOut([In, Out][MarshalAs(UnmanagedType.LPUTF8Str)]string s, int index);
+ public static void TestInOutStringParameter(string orgString, int index)
+ {
+ string passedString = orgString;
+ string expectedNativeString = passedString;
+
+ string nativeString = StringParameterInOut(passedString, index);
+ if (!(nativeString == expectedNativeString))
+ {
+ throw new Exception("StringParameterInOut: nativeString != expecedNativeString ");
+ }
+ }
+
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.LPUTF8Str)]
+ public static extern string StringParameterOut([Out][MarshalAs(UnmanagedType.LPUTF8Str)]string s, int index);
+ public static void TestOutStringParameter(string orgString, int index)
+ {
+ string passedString = orgString;
+ string expecedNativeString = passedString;
+ string nativeString = StringParameterInOut(passedString, index);
+ if (!(nativeString == expecedNativeString))
+ {
+ throw new Exception("StringParameterInOut: nativeString != expecedNativeString ");
+ }
+ }
+
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void StringParameterRefOut([MarshalAs(UnmanagedType.LPUTF8Str)]out string s, int index);
+ public static void TestStringPassByOut(string orgString, int index)
+ {
+ // out string
+ string expectedNative = string.Empty;
+ StringParameterRefOut(out expectedNative, index);
+ if (orgString != expectedNative)
+ {
+ throw new Exception("TestStringPassByOut : expectedNative != outString");
+ }
+ }
+
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void StringParameterRef([MarshalAs(UnmanagedType.LPUTF8Str)]ref string s, int index);
+ public static void TestStringPassByRef(string orgString, int index)
+ {
+ string orgCopy = new string(orgString.ToCharArray());
+ StringParameterRef(ref orgString, index);
+ if (orgString != orgCopy)
+ {
+ throw new Exception("TestStringPassByOut : string mismatch");
+ }
+ }
+
+ public static void EmptyStringTest()
+ {
+ StringParameterInOut(string.Empty, 0);
+ StringParameterOut(string.Empty, 0);
+ }
+}
+
+// UTF8 stringbuilder
+class UTF8StringBuilderTests
+{
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void StringBuilderParameterInOut([In, Out][MarshalAs(UnmanagedType.LPUTF8Str)]StringBuilder s, int index);
+ public static void TestInOutStringBuilderParameter(string expectedString, int index)
+ {
+ StringBuilder nativeStrBuilder = new StringBuilder(expectedString);
+ StringBuilderParameterInOut(nativeStrBuilder, index);
+
+ if (!nativeStrBuilder.ToString().Equals(expectedString))
+ {
+ throw new Exception("TestInOutStringBuilderParameter: nativeString != expecedNativeString ");
+ }
+ }
+
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void StringBuilderParameterOut([Out][MarshalAs(UnmanagedType.LPUTF8Str)]StringBuilder s, int index);
+ public static void TestOutStringBuilderParameter(string expectedString, int index)
+ {
+ // string builder capacity
+ StringBuilder nativeStringBuilder = new StringBuilder(expectedString.Length);
+ StringBuilderParameterOut(nativeStringBuilder, index);
+
+ if (!nativeStringBuilder.ToString().Equals(expectedString))
+ {
+ throw new Exception("TestOutStringBuilderParameter: string != expecedString ");
+ }
+ }
+
+
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.LPUTF8Str,SizeConst = 512)]
+ public static extern StringBuilder StringBuilderParameterReturn(int index);
+ public static void TestReturnStringBuilder(string expectedReturn, int index)
+ {
+ StringBuilder nativeString = StringBuilderParameterReturn(index);
+ if (!expectedReturn.Equals(nativeString.ToString()))
+ {
+ throw new Exception(string.Format( "TestReturnStringBuilder: nativeString {0} != expecedNativeString {1}",nativeString.ToString(),expectedReturn) );
+ }
+ }
+}
+
+// UTF8 string as struct field
+class UTF8StructMarshalling
+{
+ public struct Utf8Struct
+ {
+ [MarshalAs(UnmanagedType.LPUTF8Str)]
+ public string FirstName;
+ public int index;
+ }
+
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void TestStructWithUtf8Field(Utf8Struct utfStruct);
+ public static void TestUTF8StructMarshalling(string[] utf8Strings)
+ {
+ Utf8Struct utf8Struct = new Utf8Struct();
+ for (int i = 0; i < utf8Strings.Length; i++)
+ {
+ utf8Struct.FirstName = utf8Strings[i];
+ utf8Struct.index = i;
+ TestStructWithUtf8Field(utf8Struct);
+ }
+ }
+}
+
+// UTF8 string as delegate parameter
+class UTF8DelegateMarshalling
+{
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void DelegateUTF8Parameter([MarshalAs(UnmanagedType.LPUTF8Str)]string utf8String, int index);
+
+
+ [DllImport("UTF8TestNative", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void Utf8DelegateAsParameter(DelegateUTF8Parameter param);
+
+
+ public static void TestUTF8DelegateMarshalling()
+ {
+ Utf8DelegateAsParameter(new DelegateUTF8Parameter(Utf8StringCallback));
+ }
+
+ public static void Utf8StringCallback(string nativeString, int index)
+ {
+ if (string.CompareOrdinal(nativeString, Test.utf8Strings[index]) != 0)
+ {
+ throw new Exception("Utf8StringCallback string do not match");
+ }
+ }
+}
+
+class Test
+{
+ //test strings
+ public static string[] utf8Strings = {
+ "Managed",
+ "Sîne klâwen durh die wolken sint geslagen" ,
+ "काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम्",
+ "我能吞下玻璃而不伤身体",
+ "ღმერთსი შემვედრე,შემვედრე, ნუთუ კვლა დამხსნას შემვედრე,სოფლისა შემვედრე, შემვედრე,შემვედრე,შემვედრე,შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასაშემვედრე,შემვედრე,",
+ "Τη γλώσσα μου έδωσαν ελληνική",
+ null,
+ };
+
+ public static int Main(string[] args)
+ {
+ // Test string as [In,Out] parameter
+ for (int i = 0; i < utf8Strings.Length; i++)
+ UTF8StringTests.TestInOutStringParameter(utf8Strings[i], i);
+
+ // Test string as [Out] parameter
+ for (int i = 0; i < utf8Strings.Length; i++)
+ UTF8StringTests.TestOutStringParameter(utf8Strings[i], i);
+
+ for (int i = 0; i < utf8Strings.Length - 1; i++)
+ UTF8StringTests.TestStringPassByOut(utf8Strings[i], i);
+
+ for (int i = 0; i < utf8Strings.Length - 1; i++)
+ UTF8StringTests.TestStringPassByRef(utf8Strings[i], i);
+
+
+ // Test StringBuilder as [In,Out] parameter
+ for (int i = 0; i < utf8Strings.Length - 1; i++)
+ UTF8StringBuilderTests.TestInOutStringBuilderParameter(utf8Strings[i], i);
+
+ // Test StringBuilder as [Out] parameter
+ for (int i = 0; i < utf8Strings.Length - 1; i++)
+ UTF8StringBuilderTests.TestOutStringBuilderParameter(utf8Strings[i], i);
+
+ // utf8 string as struct fields
+ UTF8StructMarshalling.TestUTF8StructMarshalling(utf8Strings);
+
+ // delegate
+ UTF8DelegateMarshalling.TestUTF8DelegateMarshalling();
+
+ // Test StringBuilder as [Out] parameter
+ for (int i = 0; i < utf8Strings.Length - 1; i++)
+ UTF8StringBuilderTests.TestReturnStringBuilder(utf8Strings[i], i);
+
+ // String.Empty tests
+ UTF8StringTests.EmptyStringTest();
+
+ return 100;
+ }
+} \ No newline at end of file
diff --git a/tests/src/Interop/StringMarshalling/UTF8/UTF8Test.csproj b/tests/src/Interop/StringMarshalling/UTF8/UTF8Test.csproj
new file mode 100644
index 0000000000..8884419a6b
--- /dev/null
+++ b/tests/src/Interop/StringMarshalling/UTF8/UTF8Test.csproj
@@ -0,0 +1,50 @@
+<?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>UTF8Test</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+ <OutputType>exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+ </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" />
+ <Compile Include="..\..\common\Assertion.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="project.json" />
+ </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> \ No newline at end of file
diff --git a/tests/src/Interop/StringMarshalling/UTF8/UTF8TestNative.cpp b/tests/src/Interop/StringMarshalling/UTF8/UTF8TestNative.cpp
new file mode 100644
index 0000000000..77e4b9c8cb
--- /dev/null
+++ b/tests/src/Interop/StringMarshalling/UTF8/UTF8TestNative.cpp
@@ -0,0 +1,314 @@
+// 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 <xplatform.h>
+
+// helper functions
+#ifdef _WIN32
+char* UTF16ToUTF8(wchar_t * pszTextUTF16)
+{
+ if ((pszTextUTF16 == NULL) || (*pszTextUTF16 == L'\0')) {
+ return 0;
+ }
+
+ size_t cchUTF16;
+ cchUTF16 = wcslen(pszTextUTF16) + 1;
+ int cbUTF8 = WideCharToMultiByte(CP_UTF8, 0,
+ pszTextUTF16,
+ (int)cchUTF16,
+ NULL,
+ 0/* request buffer size*/,
+ NULL,
+ NULL);
+
+ char *pszUTF8 = (char*)CoTaskMemAlloc(sizeof(char) * (cbUTF8 + 1));
+ int nc = WideCharToMultiByte(CP_UTF8, // convert to UTF-8
+ 0, //default flags
+ pszTextUTF16, //source wide string
+ (int)cchUTF16, // length of wide string
+ pszUTF8, // destination buffer
+ cbUTF8, // destination buffer size
+ NULL,
+ NULL);
+
+ if (!nc)
+ {
+ throw;
+ }
+
+ pszUTF8[nc] = '\0';
+ return pszUTF8;
+}
+
+wchar_t* UTF8ToUTF16(const char *utf8)
+{
+ // Special case of empty input string
+ //wszTextUTF16
+ wchar_t *wszTextUTF16 = 0;
+ if (!utf8 || !(*utf8))
+ return wszTextUTF16;
+ size_t szUtf8 = strlen(utf8);
+
+ //Get length (in wchar_t's) of resulting UTF-16 string
+ int cbUTF16 = ::MultiByteToWideChar(
+ CP_UTF8, // convert from UTF-8
+ 0, // default flags
+ utf8, // source UTF-8 string
+ (int)szUtf8, // length (in chars) of source UTF-8 string
+ NULL, // unused - no conversion done in this step
+ 0 // request size of destination buffer, in wchar_t's
+ );
+
+ wszTextUTF16 = (wchar_t*)(CoTaskMemAlloc((cbUTF16 + 1 ) * sizeof(wchar_t) ));
+ // Do the actual conversion from UTF-8 to UTF-16
+ int nc = ::MultiByteToWideChar(
+ CP_UTF8, // convert from UTF-8
+ 0, // default flags
+ utf8, // source UTF-8 string
+ (int)szUtf8, // length (in chars) of source UTF-8 string
+ wszTextUTF16, // destination buffer
+ cbUTF16); // size of destination buffer, in wchar_t's
+
+ if (!nc)
+ {
+ throw;
+ }
+ //MultiByteToWideChar do not null terminate the string when cbMultiByte is not -1
+ wszTextUTF16[nc] = '\0';
+ return wszTextUTF16;
+}
+#endif
+
+
+LPSTR build_return_string(const char* pReturn)
+{
+ char *ret = 0;
+ if (pReturn == 0 || *pReturn == 0)
+ return ret;
+
+ size_t strLength = strlen(pReturn);
+ ret = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
+ memset(ret, '\0', strLength + 1);
+ strncpy_s(ret, strLength + 1, pReturn, strLength);
+ return ret;
+}
+
+// this is the same set as in managed side , but here
+// string need to be escaped , still CL applied some local and
+// end up with different byte sequence.
+
+const int NSTRINGS = 6;
+#ifdef _WIN32
+wchar_t *utf8Strings[] = { L"Managed",
+L"S\x00EEne kl\x00E2wen durh die wolken sint geslagen" ,
+L"\x0915\x093E\x091A\x0902 \x0936\x0915\x094D\x0928\x094B\x092E\x094D\x092F\x0924\x094D\x0924\x0941\x092E\x094D \x0964 \x0928\x094B\x092A\x0939\x093F\x0928\x0938\x094D\x0924\x093F \x092E\x093E\x092E\x094D",
+L"\x6211\x80FD\x541E\x4E0B\x73BB\x7483\x800C\x4E0D\x4F24\x8EAB\x4F53",
+L"\x10E6\x10DB\x10D4\x10E0\x10D7\x10E1\x10D8 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10DC\x10E3\x10D7\x10E3 \x10D9\x10D5\x10DA\x10D0 \x10D3\x10D0\x10DB\x10EE\x10E1\x10DC\x10D0\x10E1 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E1\x10DD\x10E4\x10DA\x10D8\x10E1\x10D0 \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4, \x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0, \x10EA\x10D4\x10EA\x10EE\x10DA\x10E1, \x10EC\x10E7\x10D0\x10DA\x10E1\x10D0 \x10D3\x10D0 \x10DB\x10D8\x10EC\x10D0\x10E1\x10D0, \x10F0\x10D0\x10D4\x10E0\x10D7\x10D0 \x10D7\x10D0\x10DC\x10D0 \x10DB\x10E0\x10DD\x10DB\x10D0\x10E1\x10D0; \x10DB\x10DD\x10DB\x10EA\x10DC\x10D4\x10E1 \x10E4\x10E0\x10D7\x10D4\x10DC\x10D8 \x10D3\x10D0 \x10D0\x10E6\x10D5\x10E4\x10E0\x10D8\x10DC\x10D3\x10D4, \x10DB\x10D8\x10D5\x10F0\x10EE\x10D5\x10D3\x10D4 \x10DB\x10D0\x10E1 \x10E9\x10D4\x10DB\x10E1\x10D0 \x10DC\x10D3\x10DD\x10DB\x10D0\x10E1\x10D0, \x10D3\x10E6\x10D8\x10E1\x10D8\x10D7 \x10D3\x10D0 \x10E6\x10D0\x10DB\x10D8\x10D7 \x10D5\x10F0\x10EE\x10D4\x10D3\x10D5\x10D8\x10D3\x10D4 \x10DB\x10D6\x10D8\x10E1\x10D0 \x10D4\x10DA\x10D5\x10D0\x10D7\x10D0 \x10D9\x10E0\x10D7\x10DD\x10DB\x10D0\x10D0\x10E1\x10D0\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,\x10E8\x10D4\x10DB\x10D5\x10D4\x10D3\x10E0\x10D4,",
+L"\x03A4\x03B7 \x03B3\x03BB\x03CE\x03C3\x03C3\x03B1 \x03BC\x03BF\x03C5 \x03AD\x03B4\x03C9\x03C3\x03B1\x03BD \x03B5\x03BB\x03BB\x03B7\x03BD\x03B9\x03BA\x03AE",
+L"\0"
+};
+
+#else
+//test strings
+const char *utf8Strings[] = { "Managed",
+"Sîne klâwen durh die wolken sint geslagen",
+"काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम्",
+"我能吞下玻璃而不伤身体",
+"ღმერთსი შემვედრე,შემვედრე, ნუთუ კვლა დამხსნას შემვედრე,სოფლისა შემვედრე, შემვედრე,შემვედრე,შემვედრე,შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასაშემვედრე,შემვედრე,",
+"Τη γλώσσα μου έδωσαν ελληνική",
+"\0"
+};
+#endif
+
+// Modify the string builder in place, managed side validates.
+extern "C" DLL_EXPORT void __cdecl StringBuilderParameterInOut(/*[In,Out] StringBuilder*/ char *s, int index)
+{
+ // if string.empty
+ if (s == 0 || *s == 0)
+ return;
+
+#ifdef _WIN32
+ char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
+#else
+ char *pszTextutf8 = (char*)utf8Strings[index];
+#endif
+
+ // do byte by byte validation of in string
+ size_t szLen = strlen(s);
+ for (size_t i = 0; i < szLen; i++)
+ {
+ if (s[i] != pszTextutf8[i])
+ {
+ printf("[in] managed string do not match native string\n");
+ throw;
+ }
+ }
+
+ // modify the string inplace
+ size_t outLen = strlen(pszTextutf8);
+ for (size_t i = 0; i < outLen; i++) {
+ s[i] = pszTextutf8[i];
+ }
+ s[outLen] = '\0';
+#ifdef _WIN32
+ CoTaskMemFree(pszTextutf8);
+#endif
+}
+
+//out string builder
+extern "C" DLL_EXPORT void __cdecl StringBuilderParameterOut(/*[Out] StringBuilder*/ char *s, int index)
+{
+
+#ifdef _WIN32
+ char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
+#else
+ char *pszTextutf8 = (char*)utf8Strings[index];
+#endif
+ // modify the string inplace
+ size_t outLen = strlen(pszTextutf8);
+ for (size_t i = 0; i < outLen; i++) {
+ s[i] = pszTextutf8[i];
+ }
+ s[outLen] = '\0';
+#ifdef _WIN32
+ CoTaskMemFree(pszTextutf8);
+#endif
+}
+
+// return utf8 stringbuilder
+extern "C" DLL_EXPORT char* __cdecl StringBuilderParameterReturn(int index) {
+
+#ifdef _WIN32
+ char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
+#else
+ char *pszTextutf8 = (char*)utf8Strings[index];
+#endif
+ size_t strLength = strlen(pszTextutf8);
+ LPSTR ret = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
+ memcpy(ret, pszTextutf8, strLength);
+ ret[strLength] = '\0';
+
+#ifdef _WIN32
+ CoTaskMemFree(pszTextutf8);
+#endif
+
+ return ret;
+}
+
+extern "C" DLL_EXPORT LPSTR __cdecl StringParameterOut(/*[Out]*/ char *s, int index)
+{
+ // return a copy
+ return build_return_string(s);
+}
+
+// string
+extern "C" DLL_EXPORT LPSTR __cdecl StringParameterInOut(/*[In,Out]*/ char *s, int index)
+{
+ // return a copy
+ return build_return_string(s);
+}
+
+// Utf8 field
+typedef struct FieldWithUtf8
+{
+ char *pFirst;
+ int index;
+}FieldWithUtf8;
+
+//utf8 struct field
+extern "C" DLL_EXPORT void _cdecl TestStructWithUtf8Field(struct FieldWithUtf8 fieldStruct)
+{
+ char *pszManagedutf8 = fieldStruct.pFirst;
+ int stringIndex = fieldStruct.index;
+ char *pszNative = 0;
+ size_t outLen = 0;
+
+ if (pszManagedutf8 == 0 || *pszManagedutf8 == 0)
+ return;
+
+#ifdef _WIN32
+ pszNative = UTF16ToUTF8(utf8Strings[stringIndex]);
+#else
+ pszNative = (char*)utf8Strings[stringIndex];
+#endif
+ outLen = strlen(pszNative);
+ // do byte by byte comparision
+ for (size_t i = 0; i < outLen; i++)
+ {
+ if (pszNative[i] != pszManagedutf8[i])
+ {
+ printf("Native and managed string do not match.\n");
+ throw;
+ }
+ }
+#ifdef _WIN32
+ CoTaskMemFree(pszNative);
+#endif
+}
+
+// test c# out keyword
+extern "C" DLL_EXPORT void __cdecl StringParameterRefOut(/*out*/ char **s, int index)
+{
+#ifdef _WIN32
+ char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
+#else
+ char *pszTextutf8 = (char*)utf8Strings[index];
+#endif
+ size_t strLength = strlen(pszTextutf8);
+ *s = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
+ memcpy(*s, pszTextutf8, strLength);
+ (*s)[strLength] = '\0';
+#ifdef _WIN32
+ CoTaskMemFree(pszTextutf8);
+#endif
+}
+
+//c# ref
+extern "C" DLL_EXPORT void __cdecl StringParameterRef(/*ref*/ char **s, int index)
+{
+#ifdef _WIN32
+ char *pszTextutf8 = UTF16ToUTF8(utf8Strings[index]);
+#else
+ char *pszTextutf8 = (char*)utf8Strings[index];
+#endif
+ size_t strLength = strlen(pszTextutf8);
+ // do byte by byte validation of in string
+ size_t szLen = strlen(*s);
+ for (size_t i = 0; i < szLen; i++)
+ {
+ if ((*s)[i] != pszTextutf8[i])
+ {
+ printf("[in] managed string do not match native string\n");
+ throw;
+ }
+ }
+
+ if (*s)
+ {
+ CoTaskMemFree(*s);
+ }
+ // overwrite the orginal
+ *s = (LPSTR)(CoTaskMemAlloc(sizeof(char)* (strLength + 1)));
+ memcpy(*s, pszTextutf8, strLength);
+ (*s)[strLength] = '\0';
+#ifdef _WIN32
+ CoTaskMemFree(pszTextutf8);
+#endif
+}
+
+// delegate test
+typedef void (__cdecl * Callback)(char *text, int index);
+extern "C" DLL_EXPORT void _cdecl Utf8DelegateAsParameter(Callback managedCallback)
+{
+ for (int i = 0; i < NSTRINGS; ++i)
+ {
+ char *pszNative = 0;
+#ifdef _WIN32
+ pszNative = UTF16ToUTF8(utf8Strings[i]);
+#else
+ pszNative = (char*)utf8Strings[i];
+#endif
+ managedCallback(pszNative, i);
+ }
+} \ No newline at end of file
diff --git a/tests/src/Interop/StringMarshalling/UTF8/project.json b/tests/src/Interop/StringMarshalling/UTF8/project.json
new file mode 100644
index 0000000000..fc3f0262a9
--- /dev/null
+++ b/tests/src/Interop/StringMarshalling/UTF8/project.json
@@ -0,0 +1,15 @@
+{
+ "dependencies": {},
+ "frameworks": {
+ "dnxcore50": {}
+ },
+ "runtimes": {
+ "win7-x86": {},
+ "win7-x64": {},
+ "ubuntu.14.04-x64": {},
+ "osx.10.10-x64": {},
+ "centos.7-x64": {},
+ "rhel.7-x64": {},
+ "debian.8.2-x64": {}
+ }
+}