Add Managed->Native tests for our WinRT primitives (#23529)
authorJeremy Koritzinsky <jekoritz@microsoft.com>
Fri, 17 May 2019 00:40:23 +0000 (17:40 -0700)
committerGitHub <noreply@github.com>
Fri, 17 May 2019 00:40:23 +0000 (17:40 -0700)
* First pass generating the contracts for the WinRT tests. Managed ones are manually written, Native are generated via C++/WinRT.

* Don't overwrite the public implementation files when we run cppwinrt

* Don't output a MIDL-processed header.

* Add default constructor for BindingViewModel.

* Partial implementation of most of the native winrt component.

* Finish implementation of native winrt component.

* Get native component building correctly (cppwinrt doesn't include wrappers for the "Windows::UI::Xaml::Interop::IBindable*" collection types.

* Add WinRT primitive marshalling tests.

* Add testing for projected types used for binding.

* Add license headers to native files.

* Disable WinRT tests on non-WinRT platforms (detection copied from CoreFX).

* Use WINDOWS_SDK_VERSION variable in all locations.

* Use Windows SDK version determined by CMake in WinRT build.

* Resolve WinMDs via globs so the build can roll between different Windows SDK versions that have required APIs seamlessly.

* Add logging of cppwinrt version.

* Try to construct path to cppwinrt when finding it

* Just directly construct the cppwinrt path.

* Remove -prefix flag from cppwinrt invocation

* PR feedback.

* Fix syntax in BindableVectorWrapper.

* Disable winrt binding test on Nano Server.

* Add enum testing. Clean up WinRT tests to hopefully build on CI (or at least fail at a later point).

* Add some more logging to try to determine why an older SDK version is being picked.

* Try to define CMAKE_SYSTEM_VERSION and see if that selects the correct SDK version (it seems to work on the build.cmd script)

* Clean up WinRT CMake now that it builds on AzDO CI.

* Disable WinRT binding test on pre-Win10V1809 systems.

47 files changed:
build-test.cmd
tests/src/Common/CoreCLRTestLibrary/Assertion.cs
tests/src/Common/CoreCLRTestLibrary/Utilities.cs
tests/src/Interop/CMakeLists.txt
tests/src/Interop/WinRT/Contracts/Component.Contracts.cs [new file with mode: 0644]
tests/src/Interop/WinRT/Contracts/Component.Contracts.idl [new file with mode: 0644]
tests/src/Interop/WinRT/Contracts/NativeComponent.cs [new file with mode: 0644]
tests/src/Interop/WinRT/Contracts/WindowsRuntimeImportAttribute.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Bindings/BindingTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Bindings/NETClientBindings.csproj [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Bindings/Program.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/ArrayTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/BooleanTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/EnumTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/ExceptionTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/KeyValuePairTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/NETClientPrimitives.csproj [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/NullableTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/Program.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/StringTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/TypeTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NETClients/Primitives/UriTests.cs [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/CMakeLists.txt [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ArrayTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ArrayTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingProjectionsTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingProjectionsTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingViewModel.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingViewModel.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BooleanTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BooleanTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.EnumTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.EnumTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ExceptionTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ExceptionTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.KeyValuePairTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.KeyValuePairTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.NullableTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.NullableTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.StringTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.StringTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.TypeTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.TypeTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.UriTesting.cpp [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Component.Contracts.UriTesting.h [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/Exports.def [new file with mode: 0644]
tests/src/Interop/WinRT/NativeComponent/pch.h [new file with mode: 0644]

index 85af0d2..e1400c4 100644 (file)
@@ -206,7 +206,8 @@ if not defined VSINSTALLDIR (
 if not exist "%VSINSTALLDIR%DIA SDK" goto NoDIA
 
 pushd "%__NativeTestIntermediatesDir%"
-call "%__SourceDir%\pal\tools\gen-buildsys-win.bat" ""%__ProjectFilesDir%"" %__VSVersion% %__BuildArch%
+set __ExtraCmakeArgs="-DCMAKE_SYSTEM_VERSION=10.0"
+call "%__SourceDir%\pal\tools\gen-buildsys-win.bat" ""%__ProjectFilesDir%"" %__VSVersion% %__BuildArch% !__ExtraCmakeArgs!
 @if defined _echo @echo on
 popd
 
index e4f785a..275b308 100644 (file)
@@ -685,6 +685,16 @@ namespace TestLibrary
             }
         }
 
+        static public void OfType<T>(object obj)
+        {
+            if (!(obj is T))
+            {
+                Assert.HandleFail(
+                    "Assert.IsOfType",
+                    $"Expected an object of type [{typeof(T).AssemblyQualifiedName}], got type of type [{obj.GetType().AssemblyQualifiedName}].");
+            }
+        }
+
         /// <summary>
         /// Throws an AssertFailedException.
         /// </summary>
index 41e0e29..470ff87 100644 (file)
@@ -67,7 +67,12 @@ namespace TestLibrary
         public static bool IsLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
         public static bool IsMacOSX => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
         public static bool IsWindows7 => IsWindows && Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1;
+        public static bool IsWinRTSupported => IsWindows && !IsWindows7;
         public static bool IsWindowsNanoServer => (!IsWindowsIoTCore && GetInstallationType().Equals("Nano Server", StringComparison.OrdinalIgnoreCase));
+        
+        // Windows 10 October 2018 Update
+        public static bool IsWindows10Version1809OrGreater =>
+            IsWindows && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildNumber() >= 17763;
         public static bool IsWindowsIoTCore
         {
             get
@@ -193,6 +198,37 @@ namespace TestLibrary
             }
         }
 
+        internal static uint GetWindowsVersion()
+        {
+            if (!IsWindows)
+            {
+                return 0;
+            }
+
+            Assert.AreEqual(0, Ntdll.RtlGetVersionEx(out Ntdll.RTL_OSVERSIONINFOEX osvi));
+            return osvi.dwMajorVersion;
+        }
+        internal static uint GetWindowsMinorVersion()
+        {
+            if (!IsWindows)
+            {
+                return 0;
+            }
+
+            Assert.AreEqual(0, Ntdll.RtlGetVersionEx(out Ntdll.RTL_OSVERSIONINFOEX osvi));
+            return osvi.dwMinorVersion;
+        }
+        internal static uint GetWindowsBuildNumber()
+        {
+            if (!IsWindows)
+            {
+                return 0;
+            }
+
+            Assert.AreEqual(0, Ntdll.RtlGetVersionEx(out Ntdll.RTL_OSVERSIONINFOEX osvi));
+            return osvi.dwBuildNumber;
+        }
+
         [MethodImpl(MethodImplOptions.NoInlining)]
         private static string GetRegistryValueString(string key, string value)
         {
@@ -231,6 +267,45 @@ namespace TestLibrary
             return stringValue;
         }
 
+        private static class Ntdll
+        {
+            [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+            internal unsafe struct RTL_OSVERSIONINFOEX
+            {
+                internal uint dwOSVersionInfoSize;
+                internal uint dwMajorVersion;
+                internal uint dwMinorVersion;
+                internal uint dwBuildNumber;
+                internal uint dwPlatformId;
+                internal fixed char szCSDVersion[128];
+            }
+
+            [DllImport(nameof(Ntdll), ExactSpelling=true)]
+            private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation);
+
+            internal static unsafe int RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi)
+            {
+                osvi = new RTL_OSVERSIONINFOEX();
+                osvi.dwOSVersionInfoSize = (uint)sizeof(RTL_OSVERSIONINFOEX);
+                return RtlGetVersion(ref osvi);
+            }
+
+            internal static unsafe string RtlGetVersion()
+            {            
+                const string Version = "Microsoft Windows";
+                if (RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0)
+                {
+                    return osvi.szCSDVersion[0] != '\0' ?
+                        string.Format("{0} {1}.{2}.{3} {4}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, new string(&(osvi.szCSDVersion[0]))) :
+                        string.Format("{0} {1}.{2}.{3}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
+                }
+                else
+                {
+                    return Version;
+                }
+            }
+        }
+
         private sealed class Kernel32
         {
             public const int PRODUCT_UNDEFINED = 0;
index 26a09be..aa19c68 100644 (file)
@@ -83,6 +83,7 @@ if(WIN32)
     add_subdirectory(COM/NativeClients/Primitives)
     add_subdirectory(COM/NativeClients/Licensing)
     add_subdirectory(COM/NativeClients/DefaultInterfaces)
+    add_subdirectory(WinRT/NativeComponent)
 
     # IJW isn't supported on ARM64
     if(NOT CLR_CMAKE_PLATFORM_ARCH_ARM64)
diff --git a/tests/src/Interop/WinRT/Contracts/Component.Contracts.cs b/tests/src/Interop/WinRT/Contracts/Component.Contracts.cs
new file mode 100644 (file)
index 0000000..068bbd7
--- /dev/null
@@ -0,0 +1,118 @@
+// 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.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+
+namespace Component.Contracts
+{
+    [ComImport]
+    [Guid("971AF13A-9793-4AF7-B2F2-72D829195592")]
+    [WindowsRuntimeImport]
+    public interface IBooleanTesting
+    {
+        bool And(bool left, bool right);
+    }
+
+    [ComImport]
+    [Guid("C6F1F632-47B6-4A52-86D2-A89807ED2677")]
+    [WindowsRuntimeImport]
+    public interface IStringTesting
+    {
+        string ConcatStrings(string left, string right);
+    }
+
+    [ComImport]
+    [Guid("939D4EE5-8D41-4C4B-8948-86017CEB9244")]
+    [WindowsRuntimeImport]
+    public interface INullableTesting
+    {
+        bool IsNull(int? value);
+        int GetIntValue(int? value);
+    }
+
+    [ComImport]
+    [Guid("BB545A14-9AE7-491A-874D-1C03D239FB70")]
+    [WindowsRuntimeImport]
+    public interface ITypeTesting
+    {
+        string GetTypeName(Type type);
+    }
+
+    [ComImport]
+    [Guid("9162201d-b591-4f30-8f41-f0f79f6ecea3")]
+    [WindowsRuntimeImport]
+    public interface IExceptionTesting
+    {
+        void ThrowException(Exception ex);
+        Exception GetException(int hResultToReturn);
+    }
+
+    [ComImport]
+    [Guid("ccd10099-3a45-4382-970d-b76f52780bcd")]
+    [WindowsRuntimeImport]
+    public interface IKeyValuePairTesting
+    {
+        KeyValuePair<int, int> MakeSimplePair(int key, int value);
+        KeyValuePair<string, string> MakeMarshaledPair(string key, string value);
+        KeyValuePair<int, IEnumerable<int>> MakeProjectedPair(int key, int[] values);
+    }
+
+    [ComImport]
+    [Guid("e0af24b3-e6c6-4e89-b8d1-a332979ef398")]
+    [WindowsRuntimeImport]
+    public interface IUriTesting
+    {
+        string GetFromUri(Uri uri);
+        Uri CreateUriFromString(string uri);
+    }
+
+    [ComImport]
+    [Guid("821B532D-CC5E-4218-90AB-A8361AC92794")]
+    [WindowsRuntimeImport]
+    public interface IArrayTesting
+    {
+        int Sum(int[] array);
+        bool Xor(bool[] array);
+    }
+
+    [ComImport]
+    [Guid("4bb923ae-986a-4aad-9bfb-13e0b5ecffa4")]
+    [WindowsRuntimeImport]
+    public interface IBindingViewModel
+    {
+        INotifyCollectionChanged Collection { get; }
+        void AddElement(int i);
+        string Name { get; set; }
+    }
+
+    [ComImport]
+    [Guid("857e28e1-3e7f-4f6f-8554-efc73feba286")]
+    [WindowsRuntimeImport]
+    public interface IBindingProjectionsTesting
+    {
+        IBindingViewModel CreateViewModel();
+        IDisposable InitializeXamlFrameworkForCurrentThread();
+    }
+
+    public enum TestEnum
+    {
+        A = 1,
+        B = 2,
+        C = 3
+    }
+
+    [ComImport]
+    [Guid("d89d71b2-2671-444d-8576-536d206dea49")]
+    [WindowsRuntimeImport]
+    public interface IEnumTesting
+    {
+        TestEnum GetA();
+        Boolean IsB(TestEnum val);
+    }
+}
diff --git a/tests/src/Interop/WinRT/Contracts/Component.Contracts.idl b/tests/src/Interop/WinRT/Contracts/Component.Contracts.idl
new file mode 100644 (file)
index 0000000..9126829
--- /dev/null
@@ -0,0 +1,104 @@
+// 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 Component.Contracts
+{
+    [interface_name("Component.Contracts.IBooleanTesting", 971AF13A-9793-4AF7-B2F2-72D829195592)]
+    runtimeclass BooleanTesting
+    {
+        BooleanTesting();
+        Boolean And(Boolean left, Boolean right);
+    }
+
+    [interface_name("Component.Contracts.IStringTesting", C6F1F632-47B6-4A52-86D2-A89807ED2677)]
+    runtimeclass StringTesting
+    {
+        StringTesting();
+        String ConcatStrings(String left, String right);
+    }
+
+    [interface_name("Component.Contracts.INullableTesting", 939D4EE5-8D41-4C4B-8948-86017CEB9244)]
+    runtimeclass NullableTesting
+    {
+        NullableTesting();
+        Boolean IsNull(Windows.Foundation.IReference<Int32> value);
+        Int32 GetIntValue(Windows.Foundation.IReference<Int32> value);
+    }
+
+    [interface_name("Component.Contracts.ITypeTesting", BB545A14-9AE7-491A-874D-1C03D239FB70)]
+    runtimeclass TypeTesting
+    {
+        TypeTesting();
+        String GetTypeName(Windows.UI.Xaml.Interop.TypeName typeName);
+    }
+    
+    [interface_name("Component.Contracts.IExceptionTesting", 9162201d-b591-4f30-8f41-f0f79f6ecea3)]
+    runtimeclass ExceptionTesting
+    {
+        ExceptionTesting();
+        void ThrowException(Windows.Foundation.HResult hr);
+        Windows.Foundation.HResult GetException(Int32 hr);
+    }
+
+    [interface_name("Component.Contracts.IKeyValuePairTesting", ccd10099-3a45-4382-970d-b76f52780bcd)]
+    runtimeclass KeyValuePairTesting
+    {
+        KeyValuePairTesting();
+        Windows.Foundation.Collections.IKeyValuePair<Int32, Int32> MakeSimplePair(Int32 key, Int32 value);
+        Windows.Foundation.Collections.IKeyValuePair<String, String> MakeMarshaledPair(String key, String value);
+        Windows.Foundation.Collections.IKeyValuePair<Int32, Windows.Foundation.Collections.IIterable<Int32> > MakeProjectedPair(Int32 key, Int32[] values);
+    }
+
+    [interface_name("Component.Contracts.IUriTesting", e0af24b3-e6c6-4e89-b8d1-a332979ef398)]
+    runtimeclass UriTesting
+    {
+        UriTesting();
+        String GetFromUri(Windows.Foundation.Uri uri);
+        Windows.Foundation.Uri CreateUriFromString(String uri);
+    }
+
+    [interface_name("Component.Contracts.IArrayTesting", 821B532D-CC5E-4218-90AB-A8361AC92794)]
+    runtimeclass ArrayTesting
+    {
+        ArrayTesting();
+        Int32 Sum(Int32[] array);
+        Boolean Xor(Boolean[] array);
+    }
+
+    [uuid(4bb923ae-986a-4aad-9bfb-13e0b5ecffa4)]
+    interface IBindingViewModel
+    {
+        Windows.UI.Xaml.Interop.INotifyCollectionChanged Collection { get; };
+        void AddElement(Int32 i);
+        String Name { get; set; };
+    }
+
+    runtimeclass BindingViewModel : [default] IBindingViewModel, Windows.UI.Xaml.Data.INotifyPropertyChanged
+    {
+        BindingViewModel();
+    }
+
+    [interface_name("Component.Contracts.IBindingProjectionsTesting", 857e28e1-3e7f-4f6f-8554-efc73feba286)]
+    runtimeclass BindingProjectionsTesting
+    {
+        BindingProjectionsTesting();
+        IBindingViewModel CreateViewModel();
+        Windows.Foundation.IClosable InitializeXamlFrameworkForCurrentThread();
+    }
+
+    enum TestEnum
+    {
+        A = 1,
+        B = 2,
+        C = 3
+    };
+
+    [interface_name("Component.Contracts.IEnumTesting", d89d71b2-2671-444d-8576-536d206dea49)]
+    runtimeclass EnumTesting
+    {
+        EnumTesting();
+        TestEnum GetA();
+        Boolean IsB(TestEnum val);
+    }
+}
diff --git a/tests/src/Interop/WinRT/Contracts/NativeComponent.cs b/tests/src/Interop/WinRT/Contracts/NativeComponent.cs
new file mode 100644 (file)
index 0000000..0b4903e
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.Runtime.InteropServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+
+public static class WinRTNativeComponent
+{
+    [DllImport(nameof(WinRTNativeComponent), PreserveSig = false)]
+    private static extern IActivationFactory DllGetActivationFactory([MarshalAs(UnmanagedType.HString)] string typeName);
+
+    public static object GetObjectFromNativeComponent(string typeName)
+    {
+        return DllGetActivationFactory(typeName).ActivateInstance();
+    }
+}
diff --git a/tests/src/Interop/WinRT/Contracts/WindowsRuntimeImportAttribute.cs b/tests/src/Interop/WinRT/Contracts/WindowsRuntimeImportAttribute.cs
new file mode 100644 (file)
index 0000000..4118488
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.WindowsRuntime
+{
+    // Types decorated with this attribute are treated specially by the compiler. A "windowsruntime" bit is set in their metadata.
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Delegate, Inherited = false)]
+    internal sealed class WindowsRuntimeImportAttribute : Attribute
+    {
+        public WindowsRuntimeImportAttribute() { }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Bindings/BindingTests.cs b/tests/src/Interop/WinRT/NETClients/Bindings/BindingTests.cs
new file mode 100644 (file)
index 0000000..da88636
--- /dev/null
@@ -0,0 +1,58 @@
+// 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.Collections.Specialized;
+using System.ComponentModel;
+using System.Linq;
+using TestLibrary;
+using Component.Contracts;
+
+namespace NetClient
+{
+    public class BindingTests
+    {
+        public static void RunTest()
+        {
+            IBindingProjectionsTesting target = (IBindingProjectionsTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.BindingProjectionsTesting");
+            using (target.InitializeXamlFrameworkForCurrentThread())
+            {       
+                IBindingViewModel vm = target.CreateViewModel();
+                RunINotifyPropertyChangedTest(vm);
+                RunINotifyCollectionChangedTest(vm);
+            }
+        }
+
+        private static void RunINotifyPropertyChangedTest(IBindingViewModel viewModel)
+        {
+            bool propertyChangedEventFired = false;
+            INotifyPropertyChanged notifyPropertyChanged = (INotifyPropertyChanged)viewModel;
+            PropertyChangedEventHandler handler = (o, e) => propertyChangedEventFired = (e.PropertyName == nameof(viewModel.Name));
+            notifyPropertyChanged.PropertyChanged += handler;
+            viewModel.Name = "New Name";
+            Assert.IsTrue(propertyChangedEventFired);
+            notifyPropertyChanged.PropertyChanged -= handler;
+            propertyChangedEventFired = false;
+            viewModel.Name = "Old Name";
+            Assert.IsFalse(propertyChangedEventFired);
+        }
+
+        private static void RunINotifyCollectionChangedTest(IBindingViewModel viewModel)
+        {
+            bool notifyCollectionChangedEventFired = false;
+            int addedElement = 42;
+            viewModel.Collection.CollectionChanged += (o, e) => 
+            {
+                notifyCollectionChangedEventFired = 
+                    e.Action == NotifyCollectionChangedAction.Add
+                    && e.NewItems.Count == 1
+                    && e.NewItems[0] is int i
+                    && i == addedElement;
+            };
+
+            viewModel.AddElement(addedElement);
+
+            Assert.IsTrue(notifyCollectionChangedEventFired);
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Bindings/NETClientBindings.csproj b/tests/src/Interop/WinRT/NETClients/Bindings/NETClientBindings.csproj
new file mode 100644 (file)
index 0000000..7bc62dc
--- /dev/null
@@ -0,0 +1,33 @@
+<?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>NETClientBindings</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{85C57688-DA98-4DE3-AC9B-526E4747434C}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <ProjectTypeGuids>{209912F9-0DA1-4184-9CC1-8D583BAF4A28};{87799F5D-CEBD-499D-BDBA-B2C6105CD766}</ProjectTypeGuids>
+    <!-- Test unsupported outside of windows -->
+    <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+    <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="../../Contracts/Component.Contracts.cs" />
+    <Compile Include="../../Contracts/WindowsRuntimeImportAttribute.cs" />
+    <Compile Include="../../Contracts/NativeComponent.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="BindingTests.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="../../NativeComponent/CMakeLists.txt" />
+    <ProjectReference Include="../../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/WinRT/NETClients/Bindings/Program.cs b/tests/src/Interop/WinRT/NETClients/Bindings/Program.cs
new file mode 100644 (file)
index 0000000..75bb46a
--- /dev/null
@@ -0,0 +1,31 @@
+// 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 NetClient
+{
+    using System;
+
+    class Program
+    {
+        static int Main(string[] args)
+        {
+            if (!TestLibrary.Utilities.IsWinRTSupported || TestLibrary.Utilities.IsWindowsNanoServer || !TestLibrary.Utilities.IsWindows10Version1809OrGreater)
+            {
+                Console.WriteLine("XAML Islands are unsupported on this platform.");
+                return 100;
+            }
+
+            try
+            {
+                BindingTests.RunTest();
+            }
+            catch (System.Exception ex)
+            {
+                Console.WriteLine(ex);
+                return 101;
+            }
+            return 100;
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/ArrayTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/ArrayTests.cs
new file mode 100644 (file)
index 0000000..a4f24c2
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.Linq;
+using TestLibrary;
+
+namespace NetClient
+{
+    public class ArrayTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.IArrayTesting target = (Component.Contracts.IArrayTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.ArrayTesting");
+            TestIntArray(target);
+            TestBoolArray(target);
+        }
+
+        private static void TestIntArray(Component.Contracts.IArrayTesting target)
+        {
+            int[] array = Enumerable.Range(1, 30).ToArray();
+            Assert.AreEqual(array.Sum(), target.Sum(array));
+
+        }
+
+        private static void TestBoolArray(Component.Contracts.IArrayTesting target)
+        {
+            bool[] array = new []{ true, false, true, true, true, false, false};
+            bool expected = array.Aggregate(false, (left, right) => left ^ right);
+
+            Assert.AreEqual(expected, target.Xor(array));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/BooleanTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/BooleanTests.cs
new file mode 100644 (file)
index 0000000..479161e
--- /dev/null
@@ -0,0 +1,17 @@
+// 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 TestLibrary;
+
+namespace NetClient
+{
+    public class BooleanTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.IBooleanTesting target = (Component.Contracts.IBooleanTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.BooleanTesting");
+            Assert.IsTrue(target.And(true, true));
+            Assert.IsFalse(target.And(false, true));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/EnumTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/EnumTests.cs
new file mode 100644 (file)
index 0000000..3830405
--- /dev/null
@@ -0,0 +1,17 @@
+// 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 TestLibrary;
+
+namespace NetClient
+{
+    public class EnumTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.IEnumTesting target = (Component.Contracts.IEnumTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.EnumTesting");
+            Assert.AreEqual(Component.Contracts.TestEnum.A, target.GetA());
+            Assert.IsTrue(target.IsB(Component.Contracts.TestEnum.B));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/ExceptionTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/ExceptionTests.cs
new file mode 100644 (file)
index 0000000..a26b81f
--- /dev/null
@@ -0,0 +1,22 @@
+// 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 TestLibrary;
+
+namespace NetClient
+{
+    public class ExceptionTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.IExceptionTesting target = (Component.Contracts.IExceptionTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.ExceptionTesting");
+
+            Assert.Throws<InvalidOperationException>(() => target.ThrowException(new InvalidOperationException()));
+
+            Assert.OfType<ArgumentOutOfRangeException>(target.GetException(new ArgumentOutOfRangeException().HResult));
+            Assert.OfType<NullReferenceException>(target.GetException(new ArgumentNullException().HResult));
+            Assert.OfType<NullReferenceException>(target.GetException(new NullReferenceException().HResult));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/KeyValuePairTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/KeyValuePairTests.cs
new file mode 100644 (file)
index 0000000..622771b
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.Collections.Generic;
+using TestLibrary;
+
+namespace NetClient
+{
+    public class KeyValuePairTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.IKeyValuePairTesting target = (Component.Contracts.IKeyValuePairTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.KeyValuePairTesting");
+            TestSimplePair(target);
+            TestMarshaledPair(target);
+        }
+
+        private static void TestSimplePair(Component.Contracts.IKeyValuePairTesting target)
+        {
+            int key = 5;
+            int value = 27;
+
+            Assert.AreEqual(new KeyValuePair<int, int>(key, value), target.MakeSimplePair(key, value));
+        }
+
+        private static void TestMarshaledPair(Component.Contracts.IKeyValuePairTesting target)
+        {
+            string key = "Key";
+            string value = "Value";
+
+            Assert.AreEqual(new KeyValuePair<string, string>(key, value), target.MakeMarshaledPair(key, value));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/NETClientPrimitives.csproj b/tests/src/Interop/WinRT/NETClients/Primitives/NETClientPrimitives.csproj
new file mode 100644 (file)
index 0000000..990f513
--- /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>NETClientPrimitives</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{85C57688-DA98-4DE3-AC9B-526E4747434C}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <ProjectTypeGuids>{209912F9-0DA1-4184-9CC1-8D583BAF4A28};{87799F5D-CEBD-499D-BDBA-B2C6105CD766}</ProjectTypeGuids>
+    <!-- Test unsupported outside of windows -->
+    <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+    <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="../../Contracts/Component.Contracts.cs" />
+    <Compile Include="../../Contracts/WindowsRuntimeImportAttribute.cs" />
+    <Compile Include="../../Contracts/NativeComponent.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="BooleanTests.cs" />
+    <Compile Include="EnumTests.cs" />
+    <Compile Include="StringTests.cs" />
+    <Compile Include="NullableTests.cs" />
+    <Compile Include="TypeTests.cs" />
+    <Compile Include="ExceptionTests.cs" />
+    <Compile Include="ArrayTests.cs" />
+    <Compile Include="KeyValuePairTests.cs" />
+    <Compile Include="UriTests.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="../../NativeComponent/CMakeLists.txt" />
+    <ProjectReference Include="../../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/NullableTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/NullableTests.cs
new file mode 100644 (file)
index 0000000..ed450c2
--- /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.
+using TestLibrary;
+
+namespace NetClient
+{
+    public class NullableTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.INullableTesting target = (Component.Contracts.INullableTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.NullableTesting");
+            Assert.IsTrue(target.IsNull(null));
+            Assert.IsFalse(target.IsNull(5));
+            Assert.AreEqual(5, target.GetIntValue(5));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/Program.cs b/tests/src/Interop/WinRT/NETClients/Primitives/Program.cs
new file mode 100644 (file)
index 0000000..64bcea1
--- /dev/null
@@ -0,0 +1,38 @@
+// 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 NetClient
+{
+    using System;
+
+    class Program
+    {
+        static int Main(string[] args)
+        {
+            if (!TestLibrary.Utilities.IsWinRTSupported)
+            {
+                return 100;
+            }
+
+            try
+            {
+                BooleanTests.RunTest();
+                EnumTests.RunTest();
+                StringTests.RunTest();
+                NullableTests.RunTest();
+                TypeTests.RunTest();
+                ExceptionTests.RunTest();
+                ArrayTests.RunTest();
+                KeyValuePairTests.RunTest();
+                UriTests.RunTest();
+            }
+            catch (System.Exception ex)
+            {
+                Console.WriteLine(ex);
+                return 101;
+            }
+            return 100;
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/StringTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/StringTests.cs
new file mode 100644 (file)
index 0000000..e7fe27b
--- /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.
+using TestLibrary;
+
+namespace NetClient
+{
+    public class StringTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.IStringTesting target = (Component.Contracts.IStringTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.StringTesting");
+            string left = "Hello C++/WinRT";
+            string right = " from .NET Core";
+            Assert.AreEqual(string.Concat(left, right), target.ConcatStrings(left, right));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/TypeTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/TypeTests.cs
new file mode 100644 (file)
index 0000000..c2f1364
--- /dev/null
@@ -0,0 +1,25 @@
+// 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 TestLibrary;
+
+namespace NetClient
+{
+    public class TypeTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.ITypeTesting target = (Component.Contracts.ITypeTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.TypeTesting");
+            
+            // Non-WinRT managed types pass their assembly-qualified name
+            Assert.AreEqual(typeof(TypeTests).AssemblyQualifiedName, target.GetTypeName(typeof(TypeTests)));
+
+            // WinRT types pass their full name (not assembly-qualified)
+            Assert.AreEqual(typeof(Component.Contracts.ITypeTesting).FullName, target.GetTypeName(typeof(Component.Contracts.ITypeTesting)));
+
+            // Projected types pass the name of the type they are projected from
+            Assert.AreEqual("Windows.UI.Xaml.Interop.TypeName", target.GetTypeName(typeof(Type)));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NETClients/Primitives/UriTests.cs b/tests/src/Interop/WinRT/NETClients/Primitives/UriTests.cs
new file mode 100644 (file)
index 0000000..0d319f1
--- /dev/null
@@ -0,0 +1,19 @@
+// 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 TestLibrary;
+
+namespace NetClient
+{
+    public class UriTests
+    {
+        public static void RunTest()
+        {
+            Component.Contracts.IUriTesting target = (Component.Contracts.IUriTesting)WinRTNativeComponent.GetObjectFromNativeComponent("Component.Contracts.UriTesting");
+            Uri managedUri = new Uri("https://dot.net");
+            Assert.AreEqual(managedUri.ToString(), target.GetFromUri(managedUri));
+            Assert.AreEqual(managedUri, target.CreateUriFromString(managedUri.ToString()));
+        }
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/CMakeLists.txt b/tests/src/Interop/WinRT/NativeComponent/CMakeLists.txt
new file mode 100644 (file)
index 0000000..00cef94
--- /dev/null
@@ -0,0 +1,116 @@
+cmake_minimum_required (VERSION 2.8.12)
+project (WinRTNativeComponent)
+include_directories( ${INC_PLATFORM_DIR} )
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") 
+include_directories("../Contracts")
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+set(SOURCES
+  Component.Contracts.ArrayTesting.cpp
+  Component.Contracts.BindingProjectionsTesting.cpp
+  Component.Contracts.BindingViewModel.cpp
+  Component.Contracts.BooleanTesting.cpp
+  Component.Contracts.EnumTesting.cpp
+  Component.Contracts.ExceptionTesting.cpp
+  Component.Contracts.KeyValuePairTesting.cpp
+  Component.Contracts.NullableTesting.cpp
+  Component.Contracts.StringTesting.cpp
+  Component.Contracts.TypeTesting.cpp
+  Component.Contracts.UriTesting.cpp
+)
+
+set (MIDL_GENERATED_WINMD ${CMAKE_CURRENT_BINARY_DIR}/WinMD/Component.Contracts.winmd)
+file(TO_NATIVE_PATH ${MIDL_GENERATED_WINMD} MIDL_GENERATED_WINMD_WINDOWS_PATH)
+
+if(NOT DEFINED CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION OR CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION STREQUAL "" )
+  message(FATAL_ERROR "Windows SDK is required for the WinRT interop tests build.")
+else()
+  message("Using Windows SDK version ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} for WinRT interop tests.")
+endif()
+
+set (PROGRAM_FILES_X86 "ProgramFiles(x86)")
+set (WINDOWS_KITS_DIR "$ENV{${PROGRAM_FILES_X86}}/Windows Kits/10")
+if (NOT EXISTS ${WINDOWS_KITS_DIR})
+  set (WINDOWS_KITS_DIR "$ENV{ProgramFiles}/Windows Kits/10")
+endif()
+set (METADATA_DIR "${WINDOWS_KITS_DIR}/References/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/windows.foundation.foundationcontract/*" )
+set (REFERENCE_WINMDS
+  "${WINDOWS_KITS_DIR}/References/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/Windows.Foundation.FoundationContract/*/Windows.Foundation.FoundationContract.winmd"
+  "${WINDOWS_KITS_DIR}/References/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/Windows.Foundation.UniversalApiContract/*/Windows.Foundation.UniversalApiContract.winmd")
+
+file(GLOB RESOLVED_METADATA_DIR ${METADATA_DIR})
+file(TO_NATIVE_PATH ${RESOLVED_METADATA_DIR} METADATA_DIR_ARGUMENT)
+
+file(GLOB_RECURSE RESOLVED_REFERENCE_WINMDS ${REFERENCE_WINMDS})
+
+set (REFERENCE_WINMD_ARGS "")
+foreach(WINMD ${RESOLVED_REFERENCE_WINMDS})
+  file(TO_NATIVE_PATH ${WINMD} WINMD_WINDOWS)
+  set(WINMD_WINDOWS "${WINMD_WINDOWS}")
+  string(PREPEND WINMD_WINDOWS "/reference")
+  list(APPEND REFERENCE_WINMD_ARGS ${WINMD_WINDOWS})
+endforeach()
+
+set (MIDL_FILE ../Contracts/Component.Contracts.idl)
+set (MIDL_COMMAND_LINE_ARGS
+  /winrt
+  /metadata_dir ${METADATA_DIR_ARGUMENT}
+  /W1
+  /enum_class 
+  /ns_prefix 
+  /target "NT60"  
+  /nomidl 
+  /h "nul"
+  ${REFERENCE_WINMD_ARGS}
+)
+
+find_program(MIDLRT midlrt)
+
+add_custom_command(
+  OUTPUT ${MIDL_GENERATED_WINMD}
+  COMMAND ${MIDLRT} ${MIDL_COMMAND_LINE_ARGS} ${MIDL_FILE} /winmd ${MIDL_GENERATED_WINMD_WINDOWS_PATH}
+  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+  DEPENDS ${MIDL_FILE}
+)
+
+set_source_files_properties(${MIDL_GENERATED_WINMD} PROPERTIES GENERATED TRUE)
+
+set (CPP_WINRT_OUTPUT_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/Generated)
+
+set (CPP_WINRT_OUTPUT_FILES
+  ${CPP_WINRT_OUTPUT_FOLDER}/winrt/impl/Component.Contracts.0.h
+  ${CPP_WINRT_OUTPUT_FOLDER}/winrt/impl/Component.Contracts.1.h
+  ${CPP_WINRT_OUTPUT_FOLDER}/winrt/impl/Component.Contracts.2.h
+  ${CPP_WINRT_OUTPUT_FOLDER}/winrt/Component.Contracts.h
+  ${CPP_WINRT_OUTPUT_FOLDER}/module.g.cpp
+)
+
+include_directories(${CPP_WINRT_OUTPUT_FOLDER})
+
+find_program(CPPWINRT cppwinrt)
+
+add_custom_command(
+  OUTPUT ${CPP_WINRT_OUTPUT_FILES}
+  COMMAND ${CPPWINRT} -name Contracts -comp ${CMAKE_CURRENT_SOURCE_DIR} -in ${MIDL_GENERATED_WINMD} -ref ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} -out ${CPP_WINRT_OUTPUT_FOLDER}
+  DEPENDS ${MIDL_GENERATED_WINMD}
+)
+
+set_source_files_properties(${CPP_WINRT_OUTPUT_FILES} PROPERTIES GENERATED TRUE)
+
+list(APPEND SOURCES ${CPP_WINRT_OUTPUT_FOLDER}/module.g.cpp)
+
+if (WIN32)
+  list(APPEND SOURCES Exports.def)
+endif()
+
+# add the executable
+add_library (WinRTNativeComponent SHARED ${SOURCES})
+target_link_libraries(WinRTNativeComponent ${LINK_LIBRARIES_ADDITIONAL})
+set_target_properties(WinRTNativeComponent PROPERTIES CXX_STANDARD 17)
+
+if(WIN32)
+  target_link_libraries(WinRTNativeComponent RuntimeObject.lib)
+endif()
+
+# add the install targets
+install (TARGETS WinRTNativeComponent DESTINATION bin)
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ArrayTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ArrayTesting.cpp
new file mode 100644 (file)
index 0000000..3c5dafc
--- /dev/null
@@ -0,0 +1,19 @@
+// 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 "pch.h"
+#include "Component.Contracts.ArrayTesting.h"
+#include <numeric>
+
+namespace winrt::Component::Contracts::implementation
+{
+    int32_t ArrayTesting::Sum(array_view<int32_t const> array)
+    {
+        return std::accumulate(array.begin(), array.end(), 0);
+    }
+
+    bool ArrayTesting::Xor(array_view<bool const> array)
+    {
+        return std::accumulate(array.begin(), array.end(), false, [](bool left, bool right) { return left ^ right; });
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ArrayTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ArrayTesting.h
new file mode 100644 (file)
index 0000000..5ad383b
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/ArrayTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct ArrayTesting : ArrayTestingT<ArrayTesting>
+    {
+        ArrayTesting() = default;
+
+        int32_t Sum(array_view<int32_t const> array);
+        bool Xor(array_view<bool const> array);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct ArrayTesting : ArrayTestingT<ArrayTesting, implementation::ArrayTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingProjectionsTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingProjectionsTesting.cpp
new file mode 100644 (file)
index 0000000..5c32369
--- /dev/null
@@ -0,0 +1,20 @@
+// 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 "pch.h"
+#include "Component.Contracts.BindingProjectionsTesting.h"
+#include "Component.Contracts.BindingViewModel.h"
+#include <winrt/Windows.UI.Xaml.Hosting.h>
+
+namespace winrt::Component::Contracts::implementation
+{
+    Component::Contracts::IBindingViewModel BindingProjectionsTesting::CreateViewModel()
+    {
+        return make<BindingViewModel>();
+    }
+
+    Windows::Foundation::IClosable BindingProjectionsTesting::InitializeXamlFrameworkForCurrentThread()
+    {
+        return Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingProjectionsTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingProjectionsTesting.h
new file mode 100644 (file)
index 0000000..3813840
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/BindingProjectionsTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct BindingProjectionsTesting : BindingProjectionsTestingT<BindingProjectionsTesting>
+    {
+        BindingProjectionsTesting() = default;
+
+        Component::Contracts::IBindingViewModel CreateViewModel();
+
+        Windows::Foundation::IClosable InitializeXamlFrameworkForCurrentThread();
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct BindingProjectionsTesting : BindingProjectionsTestingT<BindingProjectionsTesting, implementation::BindingProjectionsTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingViewModel.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingViewModel.cpp
new file mode 100644 (file)
index 0000000..47b8dff
--- /dev/null
@@ -0,0 +1,40 @@
+// 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 "pch.h"
+#include "Component.Contracts.BindingViewModel.h"
+#include <xplatform.h>
+
+namespace winrt::Component::Contracts::implementation
+{
+    Windows::UI::Xaml::Interop::INotifyCollectionChanged BindingViewModel::Collection()
+    {
+        return m_collection;
+    }
+
+    void BindingViewModel::AddElement(int32_t i)
+    {
+        m_collection.push_back(i);
+    }
+
+    hstring BindingViewModel::Name()
+    {
+        return m_name;
+    }
+
+    void BindingViewModel::Name(hstring const& value)
+    {
+        m_name = value;
+        m_propertyChangedEvent(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs(hstring(W("Name"))));
+    }
+
+    winrt::event_token BindingViewModel::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
+    {
+        return m_propertyChangedEvent.add(handler);
+    }
+
+    void BindingViewModel::PropertyChanged(winrt::event_token const& token) noexcept
+    {
+        m_propertyChangedEvent.remove(token);
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingViewModel.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BindingViewModel.h
new file mode 100644 (file)
index 0000000..d394432
--- /dev/null
@@ -0,0 +1,161 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/BindingViewModel.g.h"
+#include <vector>
+
+template<typename T>
+struct BindableIteratorWrapper : winrt::implements<BindableIteratorWrapper<T>, winrt::Windows::UI::Xaml::Interop::IBindableIterator>
+{
+    BindableIteratorWrapper(winrt::Windows::Foundation::Collections::IIterator<T>&& iterator)
+        :m_iterator(std::move(iterator))
+    {}
+
+    winrt::Windows::Foundation::IInspectable Current()
+    {
+        return winrt::box_value(m_iterator.Current());
+    }
+
+    bool HasCurrent()
+    {
+        return m_iterator.HasCurrent();
+    }
+
+    bool MoveNext()
+    {
+        return m_iterator.MoveNext();
+    }
+
+private:
+    winrt::Windows::Foundation::Collections::IIterator<T> m_iterator;
+};
+
+template<typename T>
+struct BindableVectorWrapper : winrt::implements<BindableVectorWrapper<T>, winrt::Windows::UI::Xaml::Interop::IBindableVector>
+{
+    BindableVectorWrapper(winrt::Windows::Foundation::Collections::IVector<T>&& elements)
+        :m_elements(std::move(elements))
+    {
+    }
+
+    winrt::Windows::UI::Xaml::Interop::IBindableIterator First()
+    {
+        return winrt::make<BindableIteratorWrapper<int32_t>>(m_elements.First());
+    }
+
+    uint32_t Size()
+    {
+        return m_elements.Size();
+    }
+
+    void Append(winrt::Windows::Foundation::IInspectable const& value)
+    {
+        m_elements.Append(winrt::unbox_value<T>(value));
+    }
+
+    void Clear()
+    {
+        m_elements.Clear();
+    }
+
+    winrt::Windows::Foundation::IInspectable GetAt(uint32_t index)
+    {
+        return winrt::box_value(m_elements.GetAt(index));
+    }
+
+    winrt::Windows::UI::Xaml::Interop::IBindableVectorView GetView()
+    {
+        throw winrt::hresult_not_implemented();
+    }
+
+    bool IndexOf(winrt::Windows::Foundation::IInspectable const& value, uint32_t& index)
+    {
+        return m_elements.IndexOf(winrt::unbox_value<T>(value), index);
+    }
+
+    void InsertAt(uint32_t index, winrt::Windows::Foundation::IInspectable const& value)
+    {
+        m_elements.InsertAt(index, winrt::unbox_value<int32_t>(value));
+    }
+
+    void RemoveAt(uint32_t index)
+    {
+        m_elements.RemoveAt(index);
+    }
+
+    void RemoveAtEnd()
+    {
+        m_elements.RemoveAtEnd();
+    }
+
+    void SetAt(uint32_t index, winrt::Windows::Foundation::IInspectable const& value)
+    {
+        m_elements.SetAt(index, winrt::unbox_value<int32_t>(value));
+    }
+private:
+    winrt::Windows::Foundation::Collections::IVector<T> m_elements;
+};
+
+template<typename T, typename Container = std::vector<T>>
+struct ObservableCollection : winrt::implements<ObservableCollection<T, Container>, winrt::Windows::UI::Xaml::Interop::INotifyCollectionChanged>
+{
+    ObservableCollection() = default;
+
+    winrt::event_token CollectionChanged(winrt::Windows::UI::Xaml::Interop::NotifyCollectionChangedEventHandler const& handler)
+    {
+        return m_CollectionChangedEvent.add(handler);
+    }
+
+    void CollectionChanged(winrt::event_token const& token) noexcept
+    {
+        m_CollectionChangedEvent.remove(token);
+    }
+
+    void push_back(const T& value)
+    {
+        m_elements.push_back(value);
+
+        winrt::Windows::UI::Xaml::Interop::NotifyCollectionChangedEventArgs args(
+            winrt::Windows::UI::Xaml::Interop::NotifyCollectionChangedAction::Add,
+            winrt::make<BindableVectorWrapper<int32_t>>(winrt::single_threaded_vector(std::vector<T>{value})),
+            nullptr,
+            (int32_t)(m_elements.size() - 1),
+            -1
+        );
+        m_CollectionChangedEvent(*this, args);
+    }
+
+private:
+    Container m_elements;
+    winrt::event<winrt::Windows::UI::Xaml::Interop::NotifyCollectionChangedEventHandler> m_CollectionChangedEvent;
+};
+
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct BindingViewModel : BindingViewModelT<BindingViewModel>
+    {
+        BindingViewModel() = default;
+
+        Windows::UI::Xaml::Interop::INotifyCollectionChanged Collection();
+        void AddElement(int32_t i);
+        hstring Name();
+        void Name(hstring const& value);
+        winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
+        void PropertyChanged(winrt::event_token const& token) noexcept;
+
+    private:
+        hstring m_name;
+        winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChangedEvent;
+        ObservableCollection<int> m_collection;
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct BindingViewModel : BindingViewModelT<BindingViewModel, implementation::BindingViewModel>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BooleanTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BooleanTesting.cpp
new file mode 100644 (file)
index 0000000..16ad984
--- /dev/null
@@ -0,0 +1,13 @@
+// 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 "pch.h"
+#include "Component.Contracts.BooleanTesting.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    bool BooleanTesting::And(bool left, bool right)
+    {
+        return left && right;
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BooleanTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.BooleanTesting.h
new file mode 100644 (file)
index 0000000..c8449ef
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/BooleanTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct BooleanTesting : BooleanTestingT<BooleanTesting>
+    {
+        BooleanTesting() = default;
+
+        bool And(bool left, bool right);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct BooleanTesting : BooleanTestingT<BooleanTesting, implementation::BooleanTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.EnumTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.EnumTesting.cpp
new file mode 100644 (file)
index 0000000..07ffd92
--- /dev/null
@@ -0,0 +1,15 @@
+#include "pch.h"
+#include "Component.Contracts.EnumTesting.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    Component::Contracts::TestEnum EnumTesting::GetA()
+    {
+        return TestEnum::A;
+    }
+
+    bool EnumTesting::IsB(Component::Contracts::TestEnum const& val)
+    {
+        return val == TestEnum::B;
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.EnumTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.EnumTesting.h
new file mode 100644 (file)
index 0000000..f01dffe
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "Component/Contracts/EnumTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct EnumTesting : EnumTestingT<EnumTesting>
+    {
+        EnumTesting() = default;
+
+        Component::Contracts::TestEnum GetA();
+        bool IsB(Component::Contracts::TestEnum const& val);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct EnumTesting : EnumTestingT<EnumTesting, implementation::EnumTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ExceptionTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ExceptionTesting.cpp
new file mode 100644 (file)
index 0000000..7d99492
--- /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.
+#include "pch.h"
+#include "Component.Contracts.ExceptionTesting.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    void ExceptionTesting::ThrowException(winrt::hresult const& hr)
+    {
+        winrt::throw_hresult(hr);
+    }
+
+    winrt::hresult ExceptionTesting::GetException(int32_t hr)
+    {
+        return {hr};
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ExceptionTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.ExceptionTesting.h
new file mode 100644 (file)
index 0000000..5335986
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/ExceptionTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct ExceptionTesting : ExceptionTestingT<ExceptionTesting>
+    {
+        ExceptionTesting() = default;
+
+        void ThrowException(winrt::hresult const& hr);
+        winrt::hresult GetException(int32_t hr);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct ExceptionTesting : ExceptionTestingT<ExceptionTesting, implementation::ExceptionTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.KeyValuePairTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.KeyValuePairTesting.cpp
new file mode 100644 (file)
index 0000000..b6b9213
--- /dev/null
@@ -0,0 +1,48 @@
+// 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 "pch.h"
+#include "Component.Contracts.KeyValuePairTesting.h"
+#include <utility>
+#include <vector>
+
+template<typename K, typename V>
+struct pair_wrapper : winrt::implements<pair_wrapper<K, V>, winrt::Windows::Foundation::Collections::IKeyValuePair<K, V>>
+{
+    pair_wrapper(const K& key, const V& value)
+        :key{ key },
+        value{ value }
+    {}
+
+    K Key()
+    {
+        return key;
+    }
+
+    V Value()
+    {
+        return value;
+    }
+
+private:
+    K key;
+    V value;
+};
+
+namespace winrt::Component::Contracts::implementation
+{
+    Windows::Foundation::Collections::IKeyValuePair<int32_t, int32_t> KeyValuePairTesting::MakeSimplePair(int32_t key, int32_t value)
+    {
+        return make<pair_wrapper<int32_t, int32_t>>(key, value);
+    }
+
+    Windows::Foundation::Collections::IKeyValuePair<hstring, hstring> KeyValuePairTesting::MakeMarshaledPair(hstring const& key, hstring const& value)
+    {
+        return make<pair_wrapper<hstring, hstring>>(key, value);
+    }
+
+    Windows::Foundation::Collections::IKeyValuePair<int32_t, Windows::Foundation::Collections::IIterable<int32_t>> KeyValuePairTesting::MakeProjectedPair(int32_t key, array_view<int32_t const> values)
+    {
+        return pair_wrapper<int32_t, Windows::Foundation::Collections::IIterable<int32_t>>{key, winrt::single_threaded_vector(std::vector<int32_t>(values.begin(), values.end()))};
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.KeyValuePairTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.KeyValuePairTesting.h
new file mode 100644 (file)
index 0000000..1e8167c
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/KeyValuePairTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct KeyValuePairTesting : KeyValuePairTestingT<KeyValuePairTesting>
+    {
+        KeyValuePairTesting() = default;
+
+        Windows::Foundation::Collections::IKeyValuePair<int32_t, int32_t> MakeSimplePair(int32_t key, int32_t value);
+        Windows::Foundation::Collections::IKeyValuePair<hstring, hstring> MakeMarshaledPair(hstring const& key, hstring const& value);
+        Windows::Foundation::Collections::IKeyValuePair<int32_t, Windows::Foundation::Collections::IIterable<int32_t>> MakeProjectedPair(int32_t key, array_view<int32_t const> values);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct KeyValuePairTesting : KeyValuePairTestingT<KeyValuePairTesting, implementation::KeyValuePairTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.NullableTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.NullableTesting.cpp
new file mode 100644 (file)
index 0000000..8cbd5e2
--- /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.
+#include "pch.h"
+#include "Component.Contracts.NullableTesting.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    bool NullableTesting::IsNull(Windows::Foundation::IReference<int32_t> const& value)
+    {
+        return value == nullptr;
+    }
+
+    int32_t NullableTesting::GetIntValue(Windows::Foundation::IReference<int32_t> const& value)
+    {
+        return winrt::unbox_value<int32_t>(value);
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.NullableTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.NullableTesting.h
new file mode 100644 (file)
index 0000000..44ecd5e
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/NullableTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct NullableTesting : NullableTestingT<NullableTesting>
+    {
+        NullableTesting() = default;
+
+        bool IsNull(Windows::Foundation::IReference<int32_t> const& value);
+        int32_t GetIntValue(Windows::Foundation::IReference<int32_t> const& value);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct NullableTesting : NullableTestingT<NullableTesting, implementation::NullableTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.StringTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.StringTesting.cpp
new file mode 100644 (file)
index 0000000..7b691cd
--- /dev/null
@@ -0,0 +1,13 @@
+// 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 "pch.h"
+#include "Component.Contracts.StringTesting.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    hstring StringTesting::ConcatStrings(hstring const& left, hstring const& right)
+    {
+        return left + right;
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.StringTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.StringTesting.h
new file mode 100644 (file)
index 0000000..2d06e3e
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/StringTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct StringTesting : StringTestingT<StringTesting>
+    {
+        StringTesting() = default;
+
+        hstring ConcatStrings(hstring const& left, hstring const& right);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct StringTesting : StringTestingT<StringTesting, implementation::StringTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.TypeTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.TypeTesting.cpp
new file mode 100644 (file)
index 0000000..2cc79a8
--- /dev/null
@@ -0,0 +1,13 @@
+// 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 "pch.h"
+#include "Component.Contracts.TypeTesting.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    hstring TypeTesting::GetTypeName(Windows::UI::Xaml::Interop::TypeName const& typeName)
+    {
+        return typeName.Name;
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.TypeTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.TypeTesting.h
new file mode 100644 (file)
index 0000000..1a4b233
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/TypeTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct TypeTesting : TypeTestingT<TypeTesting>
+    {
+        TypeTesting() = default;
+
+        hstring GetTypeName(Windows::UI::Xaml::Interop::TypeName const& typeName);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct TypeTesting : TypeTestingT<TypeTesting, implementation::TypeTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.UriTesting.cpp b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.UriTesting.cpp
new file mode 100644 (file)
index 0000000..9812021
--- /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.
+#include "pch.h"
+#include "Component.Contracts.UriTesting.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    hstring UriTesting::GetFromUri(Windows::Foundation::Uri const& uri)
+    {
+        return uri.ToString();
+    }
+
+    Windows::Foundation::Uri UriTesting::CreateUriFromString(hstring const& uri)
+    {
+        return {uri};
+    }
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.UriTesting.h b/tests/src/Interop/WinRT/NativeComponent/Component.Contracts.UriTesting.h
new file mode 100644 (file)
index 0000000..c8cda59
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+#pragma once
+
+#include "Component/Contracts/UriTesting.g.h"
+
+namespace winrt::Component::Contracts::implementation
+{
+    struct UriTesting : UriTestingT<UriTesting>
+    {
+        UriTesting() = default;
+
+        hstring GetFromUri(Windows::Foundation::Uri const& uri);
+        Windows::Foundation::Uri CreateUriFromString(hstring const& uri);
+    };
+}
+
+namespace winrt::Component::Contracts::factory_implementation
+{
+    struct UriTesting : UriTestingT<UriTesting, implementation::UriTesting>
+    {
+    };
+}
diff --git a/tests/src/Interop/WinRT/NativeComponent/Exports.def b/tests/src/Interop/WinRT/NativeComponent/Exports.def
new file mode 100644 (file)
index 0000000..6e3d53b
--- /dev/null
@@ -0,0 +1,3 @@
+EXPORTS
+    DllCanUnloadNow         = WINRT_CanUnloadNow          PRIVATE
+    DllGetActivationFactory = WINRT_GetActivationFactory  PRIVATE
diff --git a/tests/src/Interop/WinRT/NativeComponent/pch.h b/tests/src/Interop/WinRT/NativeComponent/pch.h
new file mode 100644 (file)
index 0000000..ebe6de1
--- /dev/null
@@ -0,0 +1,10 @@
+// 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.
+
+// The cppwinrt tool expects there to be a pch.h file in an include-directory that includes
+// winrt/base.h.
+#ifndef PCH_H
+#define PCH_H
+#include <winrt/base.h>
+#endif