From 00ada0f77304fcc3f3182037407de261bd7c35c6 Mon Sep 17 00:00:00 2001 From: Sebastien Pouliot Date: Wed, 4 May 2016 20:14:32 -0400 Subject: [PATCH] Move parts of dontlink tests into new introspection tests (#32) Those tests needs to be run with the linker disabled since they use reflection for most of their work. The original dontlink (for linker tests) was becoming too large in some configuration (e.g. tvOS release with bitcode) but this was due to other BCL assemblies (not the introspection tests) --- .gitignore | 1 + Xamarin.Mac.sln | 332 +++++++ Xamarin.iOS.sln | 76 ++ tests/common/mac/MacTestMain.cs | 54 ++ tests/introspection/ApiBaseTest.cs | 270 ++++++ tests/introspection/ApiCMAttachmentTest.cs | 535 ++++++++++++ tests/introspection/ApiClassPtrTest.cs | 119 +++ .../introspection/ApiCoreImageFiltersTest.cs | 211 +++++ tests/introspection/ApiCtorInitTest.cs | 306 +++++++ tests/introspection/ApiFieldTest.cs | 187 ++++ tests/introspection/ApiPInvokeTest.cs | 251 ++++++ tests/introspection/ApiProtocolTest.cs | 297 +++++++ tests/introspection/ApiSelectorTest.cs | 406 +++++++++ tests/introspection/ApiSignatureTest.cs | 760 ++++++++++++++++ tests/introspection/ApiStructTest.cs | 94 ++ tests/introspection/ApiTypoTest.cs | 476 ++++++++++ tests/introspection/ApiWeakPropertyTest.cs | 110 +++ tests/introspection/CoreSelectorTest.cs | 130 +++ tests/introspection/EnvironmentVariable.cs | 19 + tests/introspection/Mac/Info.plist | 20 + tests/introspection/Mac/Mac.cs | 31 + tests/introspection/Mac/MacApiCtorInitTest.cs | 243 ++++++ tests/introspection/Mac/MacApiFieldTest.cs | 220 +++++ tests/introspection/Mac/MacApiPInvokeTest.cs | 76 ++ tests/introspection/Mac/MacApiProtocolTest.cs | 171 ++++ tests/introspection/Mac/MacApiSelectorTest.cs | 818 ++++++++++++++++++ .../introspection/Mac/MacApiSignatureTest.cs | 234 +++++ .../Mac/MacApiWeakPropertyTest.cs | 26 + .../Mac/MacCoreImageFiltersTest.cs | 47 + .../Mac/introspection-mac.csproj | 124 +++ tests/introspection/PlatformInfo.cs | 151 ++++ tests/introspection/iOS/AppDelegate.cs | 40 + .../AppIcons.appiconset/Contents.json | 221 +++++ .../AppIcons.appiconset/Icon-app-60@3x.png | Bin 0 -> 5100 bytes .../AppIcons.appiconset/icon-app-57.png | Bin 0 -> 1618 bytes .../AppIcons.appiconset/icon-app-57@2x.png | Bin 0 -> 3206 bytes .../AppIcons.appiconset/icon-app-60@2x.png | Bin 0 -> 3357 bytes .../AppIcons.appiconset/icon-app-72.png | Bin 0 -> 1820 bytes .../AppIcons.appiconset/icon-app-72@2x.png | Bin 0 -> 4093 bytes .../AppIcons.appiconset/icon-app-76.png | Bin 0 -> 2082 bytes .../AppIcons.appiconset/icon-app-76@2x.png | Bin 0 -> 4395 bytes .../AppIcons.appiconset/icon-app-83.5@2x.png | Bin 0 -> 8968 bytes tests/introspection/iOS/Info.plist | 29 + .../introspection/iOS/LaunchScreen.storyboard | 27 + tests/introspection/iOS/Main.cs | 24 + tests/introspection/iOS/iOSApiClassPtrTest.cs | 39 + tests/introspection/iOS/iOSApiCtorInitTest.cs | 315 +++++++ tests/introspection/iOS/iOSApiFieldTest.cs | 143 +++ tests/introspection/iOS/iOSApiPInvokeTest.cs | 99 +++ tests/introspection/iOS/iOSApiProtocolTest.cs | 286 ++++++ tests/introspection/iOS/iOSApiSelectorTest.cs | 608 +++++++++++++ .../introspection/iOS/iOSApiSignatureTest.cs | 180 ++++ tests/introspection/iOS/iOSApiTypoTest.cs | 55 ++ .../iOS/iOSApiWeakPropertyTest.cs | 54 ++ .../iOS/iOSCoreImageFiltersTest.cs | 36 + .../iOS/introspection-ios.csproj | 187 ++++ tests/introspection/xamarin1.png | Bin 0 -> 20775 bytes 57 files changed, 9138 insertions(+) create mode 100644 Xamarin.Mac.sln create mode 100644 tests/common/mac/MacTestMain.cs create mode 100644 tests/introspection/ApiBaseTest.cs create mode 100644 tests/introspection/ApiCMAttachmentTest.cs create mode 100644 tests/introspection/ApiClassPtrTest.cs create mode 100644 tests/introspection/ApiCoreImageFiltersTest.cs create mode 100644 tests/introspection/ApiCtorInitTest.cs create mode 100644 tests/introspection/ApiFieldTest.cs create mode 100644 tests/introspection/ApiPInvokeTest.cs create mode 100644 tests/introspection/ApiProtocolTest.cs create mode 100644 tests/introspection/ApiSelectorTest.cs create mode 100644 tests/introspection/ApiSignatureTest.cs create mode 100644 tests/introspection/ApiStructTest.cs create mode 100644 tests/introspection/ApiTypoTest.cs create mode 100644 tests/introspection/ApiWeakPropertyTest.cs create mode 100644 tests/introspection/CoreSelectorTest.cs create mode 100644 tests/introspection/EnvironmentVariable.cs create mode 100644 tests/introspection/Mac/Info.plist create mode 100644 tests/introspection/Mac/Mac.cs create mode 100644 tests/introspection/Mac/MacApiCtorInitTest.cs create mode 100644 tests/introspection/Mac/MacApiFieldTest.cs create mode 100644 tests/introspection/Mac/MacApiPInvokeTest.cs create mode 100644 tests/introspection/Mac/MacApiProtocolTest.cs create mode 100644 tests/introspection/Mac/MacApiSelectorTest.cs create mode 100644 tests/introspection/Mac/MacApiSignatureTest.cs create mode 100644 tests/introspection/Mac/MacApiWeakPropertyTest.cs create mode 100644 tests/introspection/Mac/MacCoreImageFiltersTest.cs create mode 100644 tests/introspection/Mac/introspection-mac.csproj create mode 100644 tests/introspection/PlatformInfo.cs create mode 100644 tests/introspection/iOS/AppDelegate.cs create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/Contents.json create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/Icon-app-60@3x.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-57.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-57@2x.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-60@2x.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-72.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-72@2x.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-76.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-76@2x.png create mode 100644 tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-83.5@2x.png create mode 100644 tests/introspection/iOS/Info.plist create mode 100644 tests/introspection/iOS/LaunchScreen.storyboard create mode 100644 tests/introspection/iOS/Main.cs create mode 100644 tests/introspection/iOS/iOSApiClassPtrTest.cs create mode 100644 tests/introspection/iOS/iOSApiCtorInitTest.cs create mode 100644 tests/introspection/iOS/iOSApiFieldTest.cs create mode 100644 tests/introspection/iOS/iOSApiPInvokeTest.cs create mode 100644 tests/introspection/iOS/iOSApiProtocolTest.cs create mode 100644 tests/introspection/iOS/iOSApiSelectorTest.cs create mode 100644 tests/introspection/iOS/iOSApiSignatureTest.cs create mode 100644 tests/introspection/iOS/iOSApiTypoTest.cs create mode 100644 tests/introspection/iOS/iOSApiWeakPropertyTest.cs create mode 100644 tests/introspection/iOS/iOSCoreImageFiltersTest.cs create mode 100644 tests/introspection/iOS/introspection-ios.csproj create mode 100644 tests/introspection/xamarin1.png diff --git a/.gitignore b/.gitignore index 8e8bd532f26a..04401644f017 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ bin obj packages ~.pmcs* +.DS_Store diff --git a/Xamarin.Mac.sln b/Xamarin.Mac.sln new file mode 100644 index 000000000000..16a87ed36985 --- /dev/null +++ b/Xamarin.Mac.sln @@ -0,0 +1,332 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xammac", "src\xammac.csproj", "{87042AD2-CDC9-4A53-9193-56226B668B88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mmp", "tools\mmp\mmp.csproj", "{F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Mdb", "external\mono\external\cecil\symbols\mdb\Mono.Cecil.Mdb.csproj", "{8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "external\mono\external\cecil\Mono.Cecil.csproj", "{D68133BD-1E63-496E-9EDE-4FBDBF77B486}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Linker", "external\mono\mcs\tools\linker\Mono.Linker.csproj", "{DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "libxammac", "runtime\libxammac.csproj", "{8A5B637C-E4FF-4145-B887-9347020100F4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bmac", "src\bmac.csproj", "{D2EE02C0-9BFD-477D-AC92-4DE2D8490790}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "opentk", "opentk\opentk.csproj", "{4DA3620B-D1BC-4B51-90BB-9789EF94C73C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{542D4426-F287-4126-9889-E17628DAECEA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuiUnit_NET_4_5", "external\guiunit\src\framework\GuiUnit_NET_4_5.csproj", "{D12F0F7B-8DE3-43EC-BA49-41052D065A9B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "introspection-mac", "tests\introspection\Mac\introspection-mac.csproj", "{FD385098-B3FD-4331-92BF-CC1F918E3334}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + net_2_0_Debug|Any CPU = net_2_0_Debug|Any CPU + net_2_0_Release|Any CPU = net_2_0_Release|Any CPU + net_3_5_Debug|Any CPU = net_3_5_Debug|Any CPU + net_3_5_Release|Any CPU = net_3_5_Release|Any CPU + net_4_0_Debug|Any CPU = net_4_0_Debug|Any CPU + net_4_0_Release|Any CPU = net_4_0_Release|Any CPU + silverlight_Debug|Any CPU = silverlight_Debug|Any CPU + silverlight_Release|Any CPU = silverlight_Release|Any CPU + winphone_Debug|Any CPU = winphone_Debug|Any CPU + winphone_Release|Any CPU = winphone_Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Debug|x86.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Debug|x86.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Release|Any CPU.Build.0 = Release|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Release|x86.ActiveCfg = Release|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.Release|x86.Build.0 = Release|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU + {4DA3620B-D1BC-4B51-90BB-9789EF94C73C}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|x86.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|x86.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|x86.ActiveCfg = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|x86.Build.0 = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Release|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Release|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Release|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Release|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Debug|x86.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Debug|x86.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Release|Any CPU.ActiveCfg = Release|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Release|Any CPU.Build.0 = Release|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Release|x86.ActiveCfg = Release|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.Release|x86.Build.0 = Release|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU + {87042AD2-CDC9-4A53-9193-56226B668B88}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Debug|x86.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Debug|x86.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Release|Any CPU.Build.0 = Release|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Release|x86.ActiveCfg = Release|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.Release|x86.Build.0 = Release|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU + {8A5B637C-E4FF-4145-B887-9347020100F4}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Debug|x86.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Debug|x86.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Release|Any CPU.Build.0 = Release|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Release|x86.ActiveCfg = Release|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.Release|x86.Build.0 = Release|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D2EE02C0-9BFD-477D-AC92-4DE2D8490790}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Debug|Any CPU.ActiveCfg = silverlight_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Debug|Any CPU.Build.0 = silverlight_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Release|Any CPU.ActiveCfg = silverlight_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Release|Any CPU.Build.0 = silverlight_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Debug|Any CPU.ActiveCfg = winphone_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Debug|Any CPU.Build.0 = winphone_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.ActiveCfg = winphone_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.Build.0 = winphone_Release|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Debug|x86.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Debug|x86.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Release|Any CPU.Build.0 = Release|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Release|x86.ActiveCfg = Release|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.Release|x86.Build.0 = Release|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU + {DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Debug|x86.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Debug|x86.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_2_0_Debug|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_2_0_Release|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_2_0_Release|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_3_5_Debug|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_3_5_Release|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_3_5_Release|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_4_0_Release|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.net_4_0_Release|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Release|Any CPU.ActiveCfg = Release|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Release|Any CPU.Build.0 = Release|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Release|x86.ActiveCfg = Release|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.Release|x86.Build.0 = Release|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.silverlight_Debug|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.silverlight_Debug|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.silverlight_Release|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.silverlight_Release|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.winphone_Debug|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.winphone_Debug|Any CPU.Build.0 = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.winphone_Release|Any CPU.ActiveCfg = Debug|x86 + {F3232882-0FA0-4BB6-9D9C-E2CC779EAF0D}.winphone_Release|Any CPU.Build.0 = Debug|x86 + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Release|Any CPU.Build.0 = Release|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Debug|x86.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Debug|x86.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Release|x86.ActiveCfg = Release|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.Release|x86.Build.0 = Release|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Debug|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Debug|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Release|Any CPU.ActiveCfg = Release|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Release|Any CPU.Build.0 = Release|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Debug|x86.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Debug|x86.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Release|x86.ActiveCfg = Release|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.Release|x86.Build.0 = Release|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_2_0_Debug|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_2_0_Release|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_2_0_Release|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_3_5_Debug|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_3_5_Release|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_3_5_Release|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_4_0_Debug|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_4_0_Release|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.net_4_0_Release|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.silverlight_Debug|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.silverlight_Debug|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.silverlight_Release|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.silverlight_Release|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.winphone_Debug|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.winphone_Debug|Any CPU.Build.0 = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.winphone_Release|Any CPU.ActiveCfg = Debug|x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334}.winphone_Release|Any CPU.Build.0 = Debug|x86 + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = tools\mmp\mmp.csproj + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B} = {542D4426-F287-4126-9889-E17628DAECEA} + {FD385098-B3FD-4331-92BF-CC1F918E3334} = {542D4426-F287-4126-9889-E17628DAECEA} + EndGlobalSection +EndGlobal diff --git a/Xamarin.iOS.sln b/Xamarin.iOS.sln index fcce22d12b7e..2fe3708e9b4d 100644 --- a/Xamarin.iOS.sln +++ b/Xamarin.iOS.sln @@ -7,6 +7,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "external\ceci EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Mdb", "external\cecil\symbols\mdb\Mono.Cecil.Mdb.csproj", "{8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{2BFA13F8-B568-48BF-9A70-9D43F718C523}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "introspection-ios", "tests\introspection\iOS\introspection-ios.csproj", "{208744BD-504E-47D7-9A98-1CF02454A6DA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +25,11 @@ Global silverlight_Release|Any CPU = silverlight_Release|Any CPU winphone_Debug|Any CPU = winphone_Debug|Any CPU winphone_Release|Any CPU = winphone_Release|Any CPU + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|iPhone = Debug|iPhone + Release|iPhone = Release|iPhone + DebugStaticRegistrar|iPhone = DebugStaticRegistrar|iPhone EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -47,6 +56,16 @@ Global {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Debug|iPhone.Build.0 = Debug|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Release|iPhone.ActiveCfg = Release|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.Release|iPhone.Build.0 = Release|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.DebugStaticRegistrar|iPhone.ActiveCfg = Debug|Any CPU + {A737EFCC-4348-4EB1-9C14-4FDC0975388D}.DebugStaticRegistrar|iPhone.Build.0 = Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_2_0_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU @@ -71,6 +90,16 @@ Global {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Debug|Any CPU.Build.0 = winphone_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.ActiveCfg = winphone_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.Build.0 = winphone_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|iPhoneSimulator.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|iPhoneSimulator.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|iPhoneSimulator.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|iPhoneSimulator.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|iPhone.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|iPhone.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|iPhone.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|iPhone.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.DebugStaticRegistrar|iPhone.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.DebugStaticRegistrar|iPhone.Build.0 = net_2_0_Debug|Any CPU {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|Any CPU.ActiveCfg = net_2_0_Release|Any CPU {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU @@ -95,5 +124,52 @@ Global {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|iPhoneSimulator.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|iPhoneSimulator.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|iPhoneSimulator.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|iPhoneSimulator.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|iPhone.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|iPhone.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|iPhone.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|iPhone.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.DebugStaticRegistrar|iPhone.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.DebugStaticRegistrar|iPhone.Build.0 = net_2_0_Debug|Any CPU + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Release|Any CPU.Build.0 = Release|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_2_0_Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_2_0_Release|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_2_0_Release|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_3_5_Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_3_5_Release|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_3_5_Release|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_4_0_Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_4_0_Release|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.net_4_0_Release|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.silverlight_Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.silverlight_Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.silverlight_Release|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.silverlight_Release|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.winphone_Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.winphone_Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.winphone_Release|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.winphone_Release|Any CPU.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Debug|iPhone.ActiveCfg = Debug|iPhone + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Debug|iPhone.Build.0 = Debug|iPhone + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Release|iPhone.ActiveCfg = Release|iPhone + {208744BD-504E-47D7-9A98-1CF02454A6DA}.Release|iPhone.Build.0 = Release|iPhone + {208744BD-504E-47D7-9A98-1CF02454A6DA}.DebugStaticRegistrar|iPhone.ActiveCfg = DebugStaticRegistrar|iPhone + {208744BD-504E-47D7-9A98-1CF02454A6DA}.DebugStaticRegistrar|iPhone.Build.0 = DebugStaticRegistrar|iPhone + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {208744BD-504E-47D7-9A98-1CF02454A6DA} = {2BFA13F8-B568-48BF-9A70-9D43F718C523} EndGlobalSection EndGlobal diff --git a/tests/common/mac/MacTestMain.cs b/tests/common/mac/MacTestMain.cs new file mode 100644 index 000000000000..ac20b4908c97 --- /dev/null +++ b/tests/common/mac/MacTestMain.cs @@ -0,0 +1,54 @@ +using System; +#if XAMCORE_2_0 +using AppKit; +using Foundation; +#else +using MonoMac.AppKit; +using MonoMac.Foundation; +#endif +using GuiUnit; +using NUnit.Framework; + +namespace Xamarin.Mac.Tests +{ + static class MainClass + { + static void Main(string[] args) + { + NSApplication.Init(); + NSRunLoop.Main.InvokeOnMainThread(RunTests); + NSApplication.Main(args); + } + + static void RunTests() + { + TestRunner.MainLoop = new NSRunLoopIntegration(); + TestRunner.Main(new[] { + typeof(MainClass).Assembly.Location, + "-labels", + "-noheader" + }); + } + + class NSRunLoopIntegration : NSObject, IMainLoopIntegration + { + public void InitializeToolkit () + { + } + + public void RunMainLoop () + { + } + + public void InvokeOnMainLoop (InvokerHelper helper) + { + NSApplication.SharedApplication.InvokeOnMainThread (helper.Invoke); + } + + public void Shutdown () + { + Environment.Exit (TestRunner.ExitCode); + } + } + } +} diff --git a/tests/introspection/ApiBaseTest.cs b/tests/introspection/ApiBaseTest.cs new file mode 100644 index 000000000000..fccfbc91949e --- /dev/null +++ b/tests/introspection/ApiBaseTest.cs @@ -0,0 +1,270 @@ +// +// Base test fixture for introspection tests +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2016 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using NUnit.Framework; +using Xamarin.Utils; +using System.Linq; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#if MONOTOUCH +using UIKit; +#endif +#else +#if MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.UIKit; +#endif +#endif + +namespace Introspection { + + public abstract class ApiBaseTest { + [DllImport ("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")] + protected static extern bool bool_objc_msgSend_IntPtr (IntPtr receiver, IntPtr selector, IntPtr arg1); + [DllImport ("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")] + protected static extern IntPtr IntPtr_objc_msgSend (IntPtr receiver, IntPtr selector); + + private LatchedEnvironmentVariable continueOnFailure = new LatchedEnvironmentVariable ("API_TEST_CONTINUE_ON_FAILURE"); + + StringBuilder error_output = new StringBuilder (); + + protected void AddErrorLine (string line) + { + error_output.AppendLine (line); + Console.Error.WriteLine (line); + Errors++; + } + + protected void AddErrorLine (string format, params object[] parameters) + { + AddErrorLine (string.Format (format, parameters)); + } + + /// + /// Gets or sets a value indicating whether this test fixture will continue after failures. + /// + /// + /// true if continue on failure; otherwise, false. + /// + public bool ContinueOnFailure { + get { return continueOnFailure.Value; } + set { continueOnFailure.Value = value; } + } + + + private LatchedEnvironmentVariable logProgress = new LatchedEnvironmentVariable ("API_TEST_LOG_PROGRESS"); + + /// + /// Gets or sets a value indicating whether this test fixture will log it's progress. + /// + /// + /// true if log progress; otherwise, false. + /// + public bool LogProgress { + get { return logProgress.Value; } + set { logProgress.Value = value; } + } + + protected TextWriter Writer { +#if MONOMAC + get { return Console.Out; } +#elif __WATCHOS__ + get { return Console.Out; } +#else + get { return AppDelegate.Runner.Writer; } +#endif + } + + protected int Errors; + protected void ReportError (string s, params object [] parameters) + { + if (!ContinueOnFailure) + Assert.Fail (s, parameters); + else { + Writer.Write ("[FAIL] "); + Writer.WriteLine (s, parameters); + Errors++; + } + } + + protected void AssertIfErrors (string s, params object[] parameters) + { + if (Errors == 0) + return; + + var msg = string.Format (s, parameters); + if (error_output.Length > 0) { + msg += "\n" + error_output.ToString () + "\n"; + error_output.Clear (); + } + Assert.Fail (msg); + } + + static protected Type NSObjectType = typeof (NSObject); + + protected virtual bool Skip (Attribute attribute) + { + return false; + } + + protected virtual bool SkipDueToAttribute (MemberInfo member) + { + if (member == null) + return false; + + return !member.IsAvailableOnHostPlatform () || + SkipDueToAttribute (member.DeclaringType) || + SkipDueToAttributeInProperty (member); + } + + // We need to check Availability info on PropertyInfo attributes too + // due to sometimes the Availability info only exist on the property + // and not on the property Getter or Setter, this complements the fix for bug: + // https://bugzilla.xamarin.com/show_bug.cgi?id=35176 + protected bool SkipDueToAttributeInProperty (MemberInfo member) + { + if (member == null) + return false; + + var m = member as MethodInfo; + + if (m == null || // Skip anything that is not a method + !m.Attributes.HasFlag (MethodAttributes.SpecialName) || + !m.Name.Contains ("get_")) // We want getters with SpecialName Attribute + return false; + + // FIXME: In the future we could cache this to reduce memory requirements + var property = m.DeclaringType + .GetProperties () + .SingleOrDefault (p => p.GetGetMethod () == m); + return property != null && SkipDueToAttribute (property); + } + + /// + /// Gets the assembly on which the test fixture will reflect the NSObject-derived types. + /// The default implementation returns the assembly where NSObject is defined, e.g. + /// monotouch.dll or xammac.dll. + /// You need to override this method to return the binding assembly you wish to test. + /// + /// + /// The assembly on which the fixture will execute it's tests. + /// + protected virtual Assembly Assembly { + get { return NSObjectType.Assembly; } + } + + const string libprefix = "/System/Library/Frameworks"; + static readonly string simprefix = Environment.GetEnvironmentVariable ("IPHONE_SIMULATOR_ROOT"); + + protected virtual string FindLibrary (string libname, bool requiresFullPath = false) + { + string prefix; + if (!String.IsNullOrEmpty (simprefix) && libname.StartsWith (libprefix, StringComparison.Ordinal)) { + libname = simprefix + libname; + prefix = String.Empty; + } else { + prefix = libprefix; // re-root libname + } + + switch (libname) { +#if !MONOMAC + case "AudioUnit": + libname = "AudioToolbox"; + break; +#endif + case "CoreAnimation": + // generated code uses QuartzCore correctly - even if the [Field] property is wrong + libname = "QuartzCore"; + break; + case "CoreMidi": + // generated code uses CoreMIDI correctly + libname = "CoreMIDI"; + break; + default: + if (requiresFullPath && (Path.GetDirectoryName (libname).Length == 0)) + ReportError ("[FAIL] Library '{0}' is specified without a path", libname); + break; + } + + return Path.Combine (prefix, libname + ".framework", libname); + } + + protected bool IsOSX11OrIOS9 { + get { +#if MONOMAC + return Mac.IsElCapitanOrHigher; +#elif __WATCHOS__ + return false; +#else + return UIDevice.CurrentDevice.CheckSystemVersion (9, 0); +#endif + } + } + + protected bool CheckiOSSystemVersion (int major, int minor) + { +#if __IOS__ + return UIDevice.CurrentDevice.CheckSystemVersion (major, minor); +#else + throw new InvalidOperationException ("Can only check iOS system version on iOS."); +#endif + } + + // This only works for API introduced in the same numeric version in both iOS and tvOS. + protected bool CheckiOSOrTVOSSystemVersion (int major, int minor) + { +#if __IOS__ || __TVOS__ + return UIDevice.CurrentDevice.CheckSystemVersion (major, minor); +#else + throw new InvalidOperationException ("Can only check iOS or tvOS system version on iOS or tvOS."); +#endif + } + + protected bool CheckWatchOSSystemVersion (int major, int minor) + { +#if __WATCHOS__ + throw new NotImplementedException (); +// return UIDevice.CurrentDevice.CheckSystemVersion (major, minor); +#else + throw new InvalidOperationException ("Can only check watchOS system version on watchOS."); +#endif + } + + protected bool CheckTVOSSystemVersion (int major, int minor) + { +#if __TVOS__ + return UIDevice.CurrentDevice.CheckSystemVersion (major, minor); +#else + throw new InvalidOperationException ("Can only check tvOS system version on tvOS."); +#endif + } + } +} diff --git a/tests/introspection/ApiCMAttachmentTest.cs b/tests/introspection/ApiCMAttachmentTest.cs new file mode 100644 index 000000000000..a3cced8173b6 --- /dev/null +++ b/tests/introspection/ApiCMAttachmentTest.cs @@ -0,0 +1,535 @@ +#if !__WATCHOS__ + +using System; +using System.Drawing; +using System.IO; +using System.Net; +using System.Linq; +using System.Security.Cryptography.X509Certificates; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using AudioToolbox; +using AudioUnit; +using CoreMedia; +using CoreFoundation; +using CoreGraphics; +using CoreText; +using CoreServices; +using CoreVideo; +using Foundation; +using ImageIO; +using MediaToolbox; +using SystemConfiguration; +using ObjCRuntime; +using Security; +using UIKit; +#else +using MonoTouch.AudioToolbox; +using MonoTouch.CoreMedia; +using MonoTouch.CoreFoundation; +using MonoTouch.CoreGraphics; +using MonoTouch.CoreServices; +using MonoTouch.CoreText; +using MonoTouch.CoreVideo; +using MonoTouch.Foundation; +using MonoTouch.ImageIO; +using MonoTouch.SystemConfiguration; +using MonoTouch.ObjCRuntime; +using MonoTouch.Security; +using MonoTouch.UIKit; +#endif + +#if !__TVOS__ + +#if XAMCORE_2_0 +using VideoToolbox; +#else +using MonoTouch.VideoToolbox; +#endif + +#endif + +namespace Introspection { + + [TestFixture] + public class ApiCMAttachmentTest : ApiBaseTest { + static Type CMClockType = typeof (CMClock); + static Type CMAttachmentInterfaceType = typeof (ICMAttachmentBearer); + static Type NativeObjectInterfaceType = typeof (INativeObject); + static Type DispatchSourceType = typeof (DispatchSource); + // CN=mail.google.com, O=Google Inc, L=Mountain View, S=California, C=US + static public byte[] mail_google_com = { + 0x30, 0x82, 0x03, 0x22, 0x30, 0x82, 0x02, 0x8b, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x2b, 0x9f, 0x7e, 0xe5, 0xca, 0x25, 0xa6, 0x25, 0x14, + 0x20, 0x47, 0x82, 0x75, 0x3a, 0x9b, 0xb9, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5a, + 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, + 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79, 0x29, 0x20, + 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x47, + 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x31, 0x30, + 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, + 0x33, 0x30, 0x39, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, + 0x30, 0x69, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x14, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, + 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x14, 0x0f, 0x6d, 0x61, 0x69, 0x6c, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, + 0x02, 0x81, 0x81, 0x00, 0xaf, 0x39, 0x15, 0x98, 0x68, 0xe4, 0x92, 0xfe, + 0x4f, 0x4f, 0xf1, 0xbb, 0xff, 0x0d, 0x2e, 0xb0, 0xfe, 0x25, 0xaa, 0xbd, + 0x68, 0x04, 0x67, 0x27, 0xea, 0x6c, 0x43, 0x4c, 0xa7, 0x6d, 0xcb, 0xc8, + 0x8f, 0x7e, 0x81, 0xee, 0x87, 0x26, 0x25, 0x10, 0x12, 0x54, 0x33, 0x9e, + 0xaa, 0x3d, 0x9b, 0x8f, 0x8e, 0x92, 0xb3, 0x4b, 0x01, 0xe3, 0xf9, 0x4a, + 0x29, 0xc3, 0x0f, 0xfd, 0xac, 0xb7, 0xd3, 0x4c, 0x97, 0x29, 0x3f, 0x69, + 0x55, 0xcf, 0x70, 0x83, 0x04, 0xaf, 0x2e, 0x04, 0x6e, 0x74, 0xd6, 0x0f, + 0x17, 0x09, 0xfe, 0x9e, 0x20, 0x24, 0x24, 0xe3, 0xc7, 0x68, 0x9c, 0xac, + 0x11, 0xbd, 0x92, 0xe4, 0xb2, 0x1b, 0x09, 0xf2, 0x02, 0x32, 0xbb, 0x55, + 0x1b, 0x2d, 0x16, 0x5f, 0x30, 0x12, 0x23, 0xe2, 0x4c, 0x4a, 0x8d, 0xc2, + 0xda, 0x3f, 0xe1, 0xb8, 0xbf, 0xf7, 0x3a, 0xb1, 0x86, 0xbe, 0xf0, 0xc5, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe7, 0x30, 0x81, 0xe4, 0x30, + 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, + 0x00, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2f, 0x30, 0x2d, + 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x53, 0x47, 0x43, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x28, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, + 0x42, 0x04, 0x01, 0x30, 0x72, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x66, 0x30, 0x64, 0x30, 0x22, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, + 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3e, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x32, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x5f, 0x53, 0x47, 0x43, 0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x35, 0x80, 0x11, 0xcd, 0x52, 0x3e, + 0x84, 0x29, 0xfb, 0xc1, 0x28, 0xe1, 0x20, 0xe5, 0x02, 0x8f, 0x5f, 0x71, + 0x65, 0x58, 0x1d, 0x62, 0x72, 0x57, 0x3c, 0xe6, 0x5e, 0x25, 0x61, 0xd3, + 0xcb, 0xad, 0x22, 0xf8, 0xd8, 0x81, 0xa4, 0xe7, 0xf4, 0xae, 0x7c, 0xd9, + 0xc1, 0x6d, 0xaa, 0x93, 0x0d, 0x62, 0x07, 0x9f, 0xf2, 0x67, 0x47, 0x99, + 0x34, 0x33, 0x4f, 0x3d, 0x02, 0x74, 0xf4, 0x81, 0xd6, 0x38, 0x08, 0x21, + 0xe8, 0xe2, 0xa1, 0xfa, 0x05, 0x41, 0x9c, 0x9c, 0xc9, 0xf9, 0xf3, 0xc8, + 0xa3, 0xee, 0x0d, 0xa5, 0xd7, 0x50, 0x54, 0x5e, 0x2f, 0x7d, 0x79, 0xb7, + 0x7e, 0x0a, 0x7c, 0xb6, 0xe2, 0x2c, 0xa8, 0xae, 0xfe, 0x94, 0xd7, 0xcd, + 0x16, 0x30, 0x71, 0x04, 0xaa, 0x9e, 0x79, 0xc3, 0xd2, 0xb6, 0x24, 0xa7, + 0x25, 0xab, 0xf0, 0x48, 0x8e, 0x2f, 0xc3, 0xa7, 0xbb, 0x50, 0xdd, 0x0f, + 0xcf, 0xb0, }; + + // copy-pasted from mono/mcs/class/corlib/Test/System.Security.Cryptography.X509Certificates/X509Cert20Test.cs + static public byte[] farscape_pfx = { 0x30, 0x82, 0x06, 0xA3, 0x02, 0x01, 0x03, 0x30, 0x82, 0x06, 0x63, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, 0x06, 0x54, 0x04, 0x82, 0x06, 0x50, 0x30, 0x82, 0x06, 0x4C, 0x30, 0x82, 0x03, 0x8D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, 0x03, 0x7E, 0x04, 0x82, 0x03, 0x7A, 0x30, 0x82, 0x03, 0x76, 0x30, 0x82, 0x03, 0x72, 0x06, 0x0B, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02, 0xA0, 0x82, 0x02, 0xB6, 0x30, 0x82, 0x02, 0xB2, 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, + 0x0E, 0x04, 0x08, 0x67, 0xFE, 0x3A, 0x52, 0x75, 0xF3, 0x82, 0x1F, 0x02, 0x02, 0x07, 0xD0, 0x04, 0x82, 0x02, 0x90, 0x31, 0x6B, 0x00, 0xFA, 0x73, 0xE6, 0x8D, 0x3D, 0x62, 0x93, 0x41, 0xA1, 0x44, 0x04, 0x17, 0x8D, 0x66, 0x7A, 0x75, 0x14, 0x89, 0xA8, 0xD1, 0x4D, 0x2A, 0xD7, 0x20, 0x27, 0x71, 0x58, 0x81, 0x16, 0xB5, 0xA6, 0x41, 0x75, 0x92, 0xB2, 0xF4, 0x0C, 0xAA, 0x9B, 0x00, 0x46, 0x85, 0x85, 0x3B, 0x09, 0x2A, 0x62, 0x33, 0x3F, 0x3D, 0x06, 0xC7, 0xE7, 0x16, 0x0C, 0xA7, 0x1D, 0x9C, 0xDA, 0x9D, 0xD3, 0xC9, 0x05, 0x60, 0xA5, 0xBE, 0xF0, 0x07, 0xD5, 0xA9, 0x4F, 0x8A, 0x80, 0xF8, 0x55, 0x7B, 0x7B, 0x3C, + 0xA0, 0x7C, 0x29, 0x29, 0xAB, 0xB1, 0xE1, 0x5A, 0x25, 0xE3, 0x23, 0x6A, 0x56, 0x98, 0x37, 0x68, 0xAF, 0x9C, 0x87, 0xBB, 0x21, 0x6E, 0x68, 0xBE, 0xAE, 0x65, 0x0C, 0x41, 0x8F, 0x5C, 0x3A, 0xB8, 0xB1, 0x9D, 0x42, 0x37, 0xE4, 0xA0, 0x37, 0xA6, 0xB8, 0xAC, 0x85, 0xD7, 0x85, 0x27, 0x68, 0xD0, 0xB6, 0x3D, 0xC7, 0x39, 0x92, 0x41, 0x46, 0x24, 0xDD, 0x08, 0x57, 0x22, 0x6A, 0xC0, 0xB7, 0xAD, 0x52, 0xC6, 0x7F, 0xE5, 0x74, 0x6A, 0x5E, 0x28, 0xA3, 0x85, 0xBD, 0xE8, 0xAD, 0x5D, 0xA3, 0x55, 0xE6, 0x63, 0x15, 0x56, 0x7B, 0x01, 0x26, 0x68, 0x5F, 0x11, 0xA3, 0x12, 0x37, 0x02, 0xA5, 0xD0, 0xB7, 0x73, 0x0C, 0x7C, + 0x97, 0xE1, 0xC6, 0x2F, 0x98, 0x82, 0x67, 0x2F, 0x5F, 0x3F, 0xBE, 0x32, 0x16, 0x25, 0x9D, 0x51, 0x48, 0x32, 0xCB, 0x42, 0xD1, 0x31, 0x07, 0xBE, 0x5D, 0xF8, 0xCD, 0x2C, 0x38, 0x0A, 0x33, 0x3B, 0x7B, 0x04, 0x84, 0xAE, 0x9C, 0xA7, 0x6B, 0x36, 0x39, 0x12, 0x87, 0x9D, 0x5B, 0x56, 0x00, 0x44, 0x11, 0xB1, 0xE2, 0x78, 0x14, 0x60, 0xF3, 0xE4, 0x1A, 0x08, 0x14, 0xC0, 0x9E, 0x49, 0x9F, 0xE0, 0x4C, 0xEC, 0x95, 0x15, 0x18, 0x48, 0x0E, 0xB9, 0x0B, 0x3A, 0xFE, 0x45, 0xB0, 0x2D, 0x0D, 0x4F, 0x94, 0x5A, 0x3C, 0x43, 0xB7, 0x40, 0x8E, 0x7B, 0xA2, 0x8E, 0x23, 0x9F, 0x75, 0x97, 0xE7, 0x21, 0x0D, 0xEB, 0xA3, 0x9D, + 0x6C, 0xC0, 0xDC, 0x73, 0xED, 0x15, 0x98, 0xE3, 0xE8, 0x32, 0x2C, 0x12, 0x92, 0x45, 0x25, 0x45, 0x76, 0x18, 0xF5, 0x97, 0x7F, 0xAC, 0xCE, 0xCF, 0x23, 0xF7, 0xD1, 0xCF, 0x06, 0xAB, 0x82, 0x96, 0x1F, 0xF8, 0x68, 0x4F, 0x5D, 0xE1, 0x09, 0xAA, 0xCB, 0xB3, 0x50, 0x85, 0x46, 0x72, 0x14, 0x6C, 0x49, 0x84, 0x57, 0x55, 0x00, 0x78, 0x3E, 0xD9, 0xAA, 0xBD, 0xCC, 0xE2, 0x7B, 0x18, 0xAA, 0x2E, 0x5D, 0xB9, 0x28, 0xEA, 0x8F, 0x8C, 0xFA, 0xB7, 0x06, 0x27, 0x07, 0x89, 0x41, 0x3F, 0x66, 0x1A, 0x91, 0xCA, 0xE9, 0xEC, 0x09, 0x12, 0x1C, 0x67, 0xB2, 0x2A, 0x8B, 0x4A, 0xF0, 0x97, 0x17, 0xDC, 0x3E, 0xCD, 0x9F, 0x03, + 0x15, 0xEF, 0x03, 0x84, 0x08, 0x4A, 0x73, 0xAE, 0xE4, 0x07, 0x30, 0x27, 0xF7, 0x25, 0x69, 0x9D, 0x6C, 0x7D, 0x81, 0x88, 0xCC, 0xFA, 0xD4, 0xC7, 0x64, 0x11, 0xC0, 0xC8, 0x2C, 0x23, 0xF6, 0xFF, 0x9B, 0xE3, 0xC8, 0x89, 0x85, 0x0B, 0x3E, 0x81, 0xD8, 0x9C, 0xBD, 0xD0, 0x2D, 0xCD, 0x15, 0xA9, 0x30, 0x84, 0xF7, 0x6D, 0xEF, 0x62, 0x3B, 0xA7, 0x8C, 0xC2, 0x93, 0x90, 0x6F, 0x91, 0xB4, 0x8A, 0x71, 0x4E, 0x41, 0x4E, 0x5C, 0x67, 0xB5, 0x49, 0xF8, 0x56, 0x3A, 0x83, 0x03, 0x4F, 0xB1, 0xF6, 0xB7, 0x31, 0x5B, 0x68, 0x26, 0x70, 0x89, 0xB1, 0x1E, 0x67, 0x4F, 0xBA, 0xE7, 0xD9, 0xDF, 0x91, 0xD8, 0xFB, 0x8A, 0xDD, + 0xB2, 0xD3, 0x4B, 0xBB, 0x9F, 0x5C, 0xA3, 0x04, 0x2C, 0x87, 0xBC, 0xD5, 0xBE, 0x8C, 0xD7, 0xCF, 0x9B, 0x72, 0x82, 0xA6, 0x99, 0xDA, 0xD7, 0x66, 0x48, 0xE7, 0x8F, 0xE9, 0x48, 0x56, 0x9D, 0xD2, 0xB9, 0x28, 0x84, 0x4F, 0x6A, 0x83, 0xB2, 0xB9, 0x4D, 0x91, 0x10, 0x58, 0x22, 0x4C, 0xE7, 0x9D, 0xC6, 0x0C, 0x74, 0xF4, 0x16, 0x58, 0x30, 0xB7, 0xB7, 0x96, 0x39, 0x6C, 0x5D, 0xFA, 0xB2, 0x03, 0x8C, 0x98, 0xD2, 0xC0, 0x64, 0xB8, 0x05, 0x29, 0x4F, 0xF0, 0x4C, 0x43, 0x48, 0xD3, 0xD8, 0xBD, 0xC7, 0xC1, 0xEA, 0x39, 0x2A, 0xDF, 0xD4, 0xDA, 0x79, 0x7C, 0xB9, 0x06, 0xC7, 0x10, 0x8D, 0x8B, 0xF1, 0xA8, 0x8E, 0x44, + 0x9E, 0x99, 0xFF, 0x81, 0x84, 0x8F, 0xD0, 0x38, 0xE1, 0xF0, 0x5A, 0x12, 0x5F, 0xC5, 0xA6, 0xED, 0x6D, 0xEE, 0xE7, 0x69, 0xC0, 0xA2, 0xB4, 0x13, 0xCA, 0x7A, 0x5D, 0xDE, 0x88, 0x75, 0xE7, 0xE2, 0x6D, 0x8A, 0xEC, 0x0F, 0x88, 0x3F, 0xE2, 0xCB, 0x60, 0xF0, 0x6A, 0xEC, 0xD0, 0xF4, 0x0D, 0x11, 0xC2, 0x84, 0x19, 0x67, 0x52, 0xAD, 0xC0, 0xC0, 0x20, 0x84, 0x6D, 0x7D, 0xEA, 0xD2, 0xF9, 0x3F, 0xE5, 0x58, 0x00, 0xED, 0x24, 0xD6, 0x50, 0x9B, 0x80, 0x80, 0x0A, 0x31, 0x81, 0xA8, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x02, 0x31, 0x00, 0x30, 0x13, 0x06, 0x09, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x15, 0x31, 0x06, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00, 0x30, 0x17, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x14, 0x31, 0x0A, 0x1E, 0x08, 0x00, 0x4D, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x6F, 0x30, 0x69, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x01, 0x31, 0x5C, 0x1E, 0x5A, 0x00, 0x4D, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x73, 0x00, 0x6F, 0x00, 0x66, 0x00, 0x74, 0x00, 0x20, 0x00, 0x52, 0x00, 0x53, 0x00, 0x41, 0x00, 0x20, 0x00, 0x53, 0x00, 0x43, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x6C, + 0x00, 0x20, 0x00, 0x43, 0x00, 0x72, 0x00, 0x79, 0x00, 0x70, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x67, 0x00, 0x72, 0x00, 0x61, 0x00, 0x70, 0x00, 0x68, 0x00, 0x69, 0x00, 0x63, 0x00, 0x20, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x76, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x30, 0x82, 0x02, 0xB7, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06, 0xA0, 0x82, 0x02, 0xA8, 0x30, 0x82, 0x02, 0xA4, 0x02, 0x01, 0x00, 0x30, 0x82, 0x02, 0x9D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, + 0x06, 0x30, 0x0E, 0x04, 0x08, 0xB8, 0x22, 0xEA, 0x3C, 0x70, 0x6A, 0xFC, 0x39, 0x02, 0x02, 0x07, 0xD0, 0x80, 0x82, 0x02, 0x70, 0x76, 0xBE, 0x5B, 0xD5, 0x3D, 0x05, 0xC1, 0xDB, 0x10, 0xA3, 0x02, 0xBB, 0x7F, 0x0A, 0x8B, 0x54, 0xC1, 0x7D, 0x19, 0xDA, 0x7E, 0x82, 0xDF, 0xAD, 0x6B, 0x42, 0xC2, 0x95, 0x95, 0x00, 0x6E, 0x82, 0x77, 0xD5, 0x42, 0x6E, 0x21, 0xA2, 0x95, 0xB4, 0x98, 0xF5, 0xDD, 0x18, 0x6F, 0xC4, 0xF3, 0xB6, 0x93, 0xA0, 0x6C, 0xF4, 0x34, 0x7A, 0x48, 0x72, 0x08, 0xB1, 0x28, 0x51, 0x54, 0x10, 0x7F, 0x35, 0xB2, 0xE5, 0x89, 0x5C, 0x0A, 0x14, 0x31, 0x1C, 0x9D, 0xA9, 0xE4, 0x94, 0x91, 0x28, 0x65, + 0xC4, 0xE7, 0x5E, 0xA9, 0x37, 0x08, 0x3D, 0xB1, 0x16, 0x61, 0x9D, 0xA9, 0x44, 0x6F, 0x20, 0x0C, 0x55, 0xD7, 0xCC, 0x48, 0x82, 0x13, 0x5D, 0xE1, 0xBD, 0x9D, 0xCE, 0x64, 0x28, 0x6D, 0x69, 0x4E, 0x08, 0x53, 0x09, 0xE0, 0xCC, 0xA8, 0x79, 0x04, 0xCF, 0xFA, 0x35, 0x1C, 0xA6, 0x70, 0x37, 0x64, 0x70, 0x74, 0xF8, 0xD0, 0xC4, 0x34, 0x0F, 0x71, 0xEF, 0x57, 0xC2, 0x43, 0x7D, 0xFA, 0xE5, 0x1B, 0x8C, 0x15, 0xA5, 0x08, 0x60, 0x78, 0xAF, 0xDA, 0x36, 0xDF, 0x79, 0x2D, 0xD7, 0x54, 0x35, 0xD7, 0x8D, 0x99, 0xD5, 0x81, 0xEC, 0x6D, 0x9F, 0x2D, 0x5E, 0xF8, 0x48, 0x85, 0x50, 0x20, 0x7D, 0xBB, 0x16, 0x4E, 0x39, 0x64, + 0xB7, 0xBC, 0xED, 0xA9, 0x6A, 0x7A, 0x06, 0x09, 0x6B, 0xBC, 0x2C, 0x5A, 0xE1, 0x4F, 0xD4, 0xA9, 0x82, 0x83, 0x5B, 0xBD, 0xCE, 0x14, 0x31, 0x89, 0x66, 0xB3, 0x9C, 0x31, 0x23, 0x00, 0x4B, 0x02, 0x34, 0x85, 0x30, 0x39, 0x77, 0x80, 0x5D, 0x72, 0x0A, 0xCE, 0x43, 0x2A, 0x1F, 0x02, 0x09, 0xAB, 0x2D, 0x46, 0x3A, 0x1C, 0xD2, 0x7B, 0xF6, 0x02, 0x92, 0xCA, 0xDA, 0x26, 0x0C, 0xF8, 0xE2, 0x67, 0x7E, 0xE2, 0x55, 0xB1, 0x3F, 0x6A, 0x06, 0x65, 0x6D, 0x74, 0x98, 0x59, 0xE2, 0x8A, 0x1E, 0x61, 0x03, 0x4D, 0xFC, 0x68, 0x31, 0x6A, 0xE7, 0xCF, 0x52, 0x88, 0x8E, 0x06, 0x97, 0x77, 0xB3, 0x20, 0x7E, 0x09, 0x5D, 0x3B, + 0xAF, 0x56, 0xF4, 0xE8, 0x4C, 0x69, 0x09, 0xB9, 0x80, 0x38, 0xDC, 0x66, 0x2E, 0x06, 0xF6, 0xCB, 0x1F, 0x1B, 0xAD, 0x51, 0xFF, 0xFD, 0x38, 0x8D, 0x03, 0x90, 0xCF, 0x31, 0x01, 0x30, 0xEA, 0x48, 0x4C, 0xBB, 0x40, 0x87, 0x1D, 0x97, 0x6A, 0x56, 0x4C, 0xED, 0x07, 0x23, 0x45, 0x50, 0x2F, 0x56, 0xC9, 0x90, 0x79, 0x09, 0xC5, 0x45, 0xB9, 0xAD, 0x58, 0x2B, 0x4C, 0xA3, 0x01, 0xE0, 0x2D, 0xE5, 0x30, 0xBC, 0x54, 0xEC, 0x65, 0xB4, 0x79, 0x22, 0x7D, 0x15, 0xF6, 0x28, 0xCD, 0x84, 0x7E, 0x27, 0x95, 0xA1, 0xC7, 0x82, 0x6D, 0xFB, 0xDF, 0x03, 0xD9, 0x14, 0xFE, 0x0A, 0x06, 0x6F, 0x14, 0xFF, 0x8A, 0x27, 0x80, 0x36, + 0xDC, 0xBA, 0xAE, 0xDD, 0x44, 0x15, 0xA5, 0x6E, 0x64, 0x73, 0xBD, 0xFB, 0xAE, 0x6D, 0x6F, 0x42, 0x96, 0xDF, 0x90, 0xE5, 0x6A, 0x9B, 0x05, 0xAE, 0xD5, 0x0A, 0x22, 0x88, 0xD6, 0x5D, 0x4C, 0x7B, 0xB1, 0x3A, 0xFC, 0x0C, 0x32, 0x02, 0xB1, 0x18, 0x0D, 0xAF, 0xE0, 0xFE, 0x7E, 0x07, 0x96, 0x85, 0xBB, 0xC8, 0x21, 0x68, 0x12, 0xD4, 0xC8, 0xBF, 0x91, 0x47, 0xE2, 0xF3, 0xA5, 0xA3, 0x86, 0xE6, 0x30, 0x42, 0xF5, 0xA9, 0xB9, 0x48, 0xCB, 0x18, 0xE6, 0x64, 0x3B, 0xE0, 0x8E, 0xC3, 0x03, 0x45, 0xA0, 0xED, 0x1A, 0x09, 0xFF, 0xB3, 0x99, 0x14, 0x5F, 0xDA, 0x90, 0x58, 0x61, 0x8E, 0xF7, 0x0A, 0x00, 0xC7, 0x44, 0xE7, + 0x73, 0x78, 0xC4, 0x8B, 0x39, 0xCE, 0x70, 0x0E, 0x24, 0x03, 0x95, 0x94, 0x73, 0x76, 0x10, 0x7E, 0x4C, 0xFF, 0xCA, 0x49, 0x93, 0x89, 0xD4, 0x3E, 0x1A, 0x88, 0xCC, 0x48, 0xA7, 0x78, 0x2F, 0x83, 0x4F, 0x6C, 0x33, 0x55, 0xDD, 0x7F, 0x7D, 0x4D, 0xE5, 0xCD, 0x9C, 0x3D, 0x04, 0x1E, 0xC1, 0x9B, 0x6D, 0x7E, 0x7A, 0xAC, 0x93, 0x5E, 0x2B, 0xC3, 0x85, 0x36, 0x07, 0x66, 0xE8, 0xC9, 0xC0, 0xD1, 0x54, 0xF4, 0x4C, 0x6A, 0x02, 0x24, 0x9A, 0x7D, 0x10, 0xD9, 0x79, 0x94, 0x00, 0x64, 0x63, 0x36, 0xDC, 0x35, 0x0C, 0x8F, 0x79, 0xBA, 0xC7, 0x10, 0x76, 0xF8, 0x4A, 0xD3, 0x69, 0x95, 0x23, 0x89, 0x66, 0xC4, 0x5A, 0xE7, + 0xCE, 0x21, 0xBC, 0xCB, 0xF2, 0x4F, 0x92, 0x33, 0xE7, 0x89, 0xD6, 0x23, 0xF7, 0x67, 0x5B, 0x20, 0xD9, 0xDA, 0x1A, 0xD1, 0xF6, 0x9E, 0x01, 0x83, 0x51, 0xAF, 0x35, 0x43, 0xDD, 0x3A, 0xAB, 0xCA, 0x0E, 0xED, 0x2E, 0x4D, 0x1E, 0x91, 0xCF, 0x2E, 0xA9, 0x4D, 0x08, 0xD9, 0x48, 0x30, 0x37, 0x30, 0x1F, 0x30, 0x07, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x04, 0x14, 0xA2, 0xED, 0x05, 0x50, 0x89, 0x91, 0x1D, 0xEB, 0xF6, 0x57, 0x66, 0xAF, 0x70, 0x15, 0xDD, 0x1A, 0xA1, 0x94, 0xB7, 0xB2, 0x04, 0x14, 0x09, 0xE4, 0x0B, 0xEC, 0x1D, 0x93, 0x3E, 0x32, 0x94, 0x6A, 0x95, 0x36, 0xDD, 0xBA, 0x93, 0x9D, 0x75, 0xB6, + 0x3E, 0xF5 }; + + // wrap the object so that we can use the extensions and fail + class AttachableNativeObject : ICMAttachmentBearer + { + INativeObject nativeObj; + + public AttachableNativeObject (INativeObject obj) + { + nativeObj = obj; + } + + public IntPtr Handle + { + get { return nativeObj.Handle; } + } + } + + protected virtual bool Skip (Type type) + { + return Skip (type.Name) || SkipDueToAttribute (type); + } + + protected virtual bool Skip (string nativeName) + { + if (nativeName.Contains ("`")) { + nativeName = nativeName.Substring (0, nativeName.IndexOf ("`")); + } + if (nativeName.StartsWith ("CGPDF")) // all those types crash the app + return true; + switch (nativeName) { + case "CFMachPort": + case "CFMessagePort": + case "DispatchSource": + case "AudioConverter": // does crash the tests + case "AudioFile": // does crash the tests + case "CFHTTPAuthentication": + case "CFHTTPStream": + case "SystemSound": // does crash the tests + case "MusicPlayer": // does crash the tests + case "MusicTrack": // does crash the tests + case "AUGraph": // does crash the tests + case "CGFunction": + case "CGShading": + case "CVMetalTexture": + case "CVMetalTextureCache": + case "CTRun": + case "CTRunDelegate": + case "CGImageMetadata": + case "SecKeyChain": // static class + case "VTDecompressionSession": + case "Class": // makes no sense to test + case "Selector": // makes no sense to test + case "CFRunLoopSource": + case "CFRunLoop": + case "NSZone": + case "MusicSequence": // crashes tests + case "AudioBuffers": // crashes tests + case "CGContext": + case "AudioComponent": + case "AudioUnit": + case "AURenderEventEnumerator": + case "CGLayer": + case "CMFormatDescription": + case "CMAudioFormatDescription": + case "CMVideoFormatDescription": + case "CMBlockBuffer": + case "CMSampleBuffer": + case "CVBuffer": // DOES support the API, but it has its own version and is already in the bindings, so no need ATM + case "CVImageBuffer": // same as CVBuffer + case "CVPixelBuffer": // same as CVBuffer + case "MTAudioProcessingTap": + case "Protocol": + case "MidiObject": // causes crash + case "CMClockOrTimebase": + case "MidiClient": + case "MidiPort": + case "MidiEntity": + case "MidiDevice": + case "MidiEndpoint": + case "ABMultiValue": + return true; + default: + return false; + } + } + + protected INativeObject GetINativeInstance (Type t) + { + var ctor = t.GetConstructor (Type.EmptyTypes); + if ((ctor != null) && !ctor.IsAbstract) + return ctor.Invoke (null) as INativeObject; + + if (!NativeObjectInterfaceType.IsAssignableFrom (t)) + throw new ArgumentException ("t"); + switch (t.Name) { + case "CFAllocator": + return CFAllocator.SystemDefault; + case "CFBundle": + var bundles = CFBundle.GetAll (); + if (bundles.Length > 0) + return bundles [0]; + else + throw new InvalidOperationException (string.Format ("Could not create the new instance for type {0}.", t.Name)); + case "CFNotificationCenter": + return CFNotificationCenter.Darwin; + case "CFReadStream": + case "CFStream": + CFReadStream readStream; + CFWriteStream writeStream; + CFStream.CreatePairWithSocketToHost ("www.google.com", 80, out readStream, out writeStream); + return readStream; + case "CFWriteStream": + CFStream.CreatePairWithSocketToHost ("www.google.com", 80, out readStream, out writeStream); + return writeStream; + case "CFUrl": + return CFUrl.FromFile ("/etc"); + case "AudioFile": + var path = Path.GetFullPath ("1.caf"); + var af = AudioFile.Open (CFUrl.FromFile (path), AudioFilePermission.Read, AudioFileType.CAF); + return af; + case "CFHTTPMessage": + return CFHTTPMessage.CreateEmpty (false); + case "CGBitmapContext": + byte[] data = new byte [400]; + using (CGColorSpace space = CGColorSpace.CreateDeviceRGB ()) { + return new CGBitmapContext (data, 10, 10, 8, 40, space, CGBitmapFlags.PremultipliedLast); + } + case "CGContextPDF": + var filename = Environment.GetFolderPath (Environment.SpecialFolder.CommonDocuments) + "/t.pdf"; + using (var url = new NSUrl (filename)) + return new CGContextPDF (url); + case "CGColorConverter": + var cvt = new CGColorConverterTriple () { + Space = CGColorSpace.CreateGenericRgb (), + Intent = CGColorRenderingIntent.Default, + Transform = CGColorConverterTransformType.ApplySpace + }; + return new CGColorConverter (null, cvt, cvt, cvt); + case "CGDataConsumer": + using (NSMutableData destData = new NSMutableData ()) { + return new CGDataConsumer (destData); + } + case "CGDataProvider": + filename = "xamarin1.png"; + return new CGDataProvider (filename); + case "CGFont": + return CGFont.CreateWithFontName ("Courier New"); + case "CGPattern": + return new CGPattern ( + new RectangleF (0, 0, 16, 16), + CGAffineTransform.MakeIdentity (), + 16, 16, + CGPatternTiling.NoDistortion, + true, + (cgc) => {}); + case "CMBufferQueue": + return CMBufferQueue.CreateUnsorted (2); + case "CTFont": + CTFontDescriptorAttributes fda = new CTFontDescriptorAttributes () { + FamilyName = "Courier", + StyleName = "Bold", + Size = 16.0f + }; + using (var fd = new CTFontDescriptor (fda)) + return new CTFont (fd, 10, CTFontOptions.Default); + case "CTFontCollection": + return new CTFontCollection (new CTFontCollectionOptions ()); + case "CTFontDescriptor": + fda = new CTFontDescriptorAttributes (); + return new CTFontDescriptor (fda); + case "CTTextTab": + return new CTTextTab (CTTextAlignment.Left, 2); + case "CTTypesetter": + return new CTTypesetter (new NSAttributedString ("Hello, world", + new CTStringAttributes () { + ForegroundColorFromContext = true, + Font = new CTFont ("Arial", 24) + })); + case "CTFrame": + var framesetter = new CTFramesetter (new NSAttributedString ("Hello, world", + new CTStringAttributes () { + ForegroundColorFromContext = true, + Font = new CTFont ("Arial", 24) + })); + var bPath = UIBezierPath.FromRect (new RectangleF (0, 0, 3, 3)); + return framesetter.GetFrame (new NSRange (0, 0), bPath.CGPath, null); + case "CTFramesetter": + return new CTFramesetter (new NSAttributedString ("Hello, world", + new CTStringAttributes () { + ForegroundColorFromContext = true, + Font = new CTFont ("Arial", 24) + })); + case "CTGlyphInfo": + return new CTGlyphInfo ("Zapfino", new CTFont ("Arial", 24), "Foo"); + case "CTLine": + return new CTLine (new NSAttributedString ("Hello, world", + new CTStringAttributes () { + ForegroundColorFromContext = true, + Font = new CTFont ("Arial", 24) + })); + case "CGImageDestination": + var storage = new NSMutableData (); + return CGImageDestination.Create (new CGDataConsumer (storage), "public.png", 1); + case "CGImageMetadataTag": + using (NSString name = new NSString ("tagName")) + using (var value = new NSString ("value")) + return new CGImageMetadataTag (CGImageMetadataTagNamespaces.Exif, CGImageMetadataTagPrefixes.Exif, name, CGImageMetadataType.Default, value); + case "CGImageSource": + filename = "xamarin1.png"; + return CGImageSource.FromUrl (NSUrl.FromFilename (filename)); + case "SecPolicy": + return SecPolicy.CreateSslPolicy (false, null); + case "SecIdentity": + using (var options = NSDictionary.FromObjectAndKey (new NSString ("farscape"), SecImportExport.Passphrase)) { + NSDictionary[] array; + var result = SecImportExport.ImportPkcs12 (farscape_pfx, options, out array); + if (result != SecStatusCode.Success) + throw new InvalidOperationException (string.Format ("Could not create the new instance for type {0} due to {1}.", t.Name, result)); + return new SecIdentity (array [0].LowlevelObjectForKey (SecImportExport.Identity.Handle)); + } + case "SecTrust": + X509Certificate x = new X509Certificate (mail_google_com); + using (var policy = SecPolicy.CreateSslPolicy (true, "mail.google.com")) + return new SecTrust (x, policy); + case "SslContext": + return new SslContext (SslProtocolSide.Client, SslConnectionType.Stream); + case "UIFontFeature": + return new UIFontFeature (CTFontFeatureNumberSpacing.Selector.ProportionalNumbers); + case "NetworkReachability": + return new NetworkReachability (IPAddress.Loopback, null); +#if !__TVOS__ + case "VTCompressionSession": + case "VTSession": + return VTCompressionSession.Create (1024, 768, CMVideoCodecType.H264, (sourceFrame, status, flags, buffer) => { }, null, (CVPixelBufferAttributes) null); + case "VTFrameSilo": + return VTFrameSilo.Create (); + case "VTMultiPassStorage": + return VTMultiPassStorage.Create (); +#endif + case "CFString": + return new CFString ("test"); + case "DispatchQueue": + return new DispatchQueue ("com.example.subsystem.taskXYZ"); + case "DispatchGroup": + return DispatchGroup.Create (); + case "CGColorSpace": + return CGColorSpace.CreateAcesCGLinear (); + case "CGGradient": + CGColor[] cArray = { UIColor.Black.CGColor, UIColor.Clear.CGColor, UIColor.Blue.CGColor }; + return new CGGradient (null, cArray); + case "CGImage": + filename = "xamarin1.png"; + using (var dp = new CGDataProvider (filename)) + return CGImage.FromPNG (dp, null, false, CGColorRenderingIntent.Default); + case "CGColor": + return UIColor.Black.CGColor; + case "CMClock": + CMClockError ce; + CMClock clock = CMClock.CreateAudioClock (out ce); + if (ce == CMClockError.None) + return clock; + throw new InvalidOperationException (string.Format ("Could not create the new instance for type {0}.", t.Name)); + case "CMTimebase": + clock = CMClock.CreateAudioClock (out ce); + if (ce == CMClockError.None) { + return new CMTimebase (clock); + } + throw new InvalidOperationException (string.Format ("Could not create the new instance for type {0}.", t.Name)); + case "CVPixelBufferPool": + return new CVPixelBufferPool ( + new CVPixelBufferPoolSettings (), + new CVPixelBufferAttributes (CVPixelFormatType.CV24RGB, 100, 50) + ); + case "SecCertificate": + using (var cdata = NSData.FromArray (mail_google_com)) + return new SecCertificate (cdata); + case "SecKey": + SecKey private_key; + SecKey public_key; + using (var record = new SecRecord (SecKind.Key)) { + record.KeyType = SecKeyType.RSA; + record.KeySizeInBits = 512; // it's not a performance test :) + SecKey.GenerateKeyPair (record.ToDictionary (), out public_key, out private_key); + return private_key; + } + case "SecAccessControl": + return new SecAccessControl (SecAccessible.WhenPasscodeSetThisDeviceOnly); + default: + throw new InvalidOperationException (string.Format ("Could not create the new instance for type {0}.", t.Name)); + } + } + + protected ICMAttachmentBearer GetInstance (Type t) + { + if (!CMAttachmentInterfaceType.IsAssignableFrom (t)) + throw new ArgumentException ("t"); + switch (t.Name) { + case "CMBlockBuffer": + CMBlockBufferError bbe; + var result = CMBlockBuffer.CreateEmpty (0, CMBlockBufferFlags.AssureMemoryNow, out bbe); + if (bbe == CMBlockBufferError.None) + return result; + else + throw new InvalidOperationException (string.Format ("Could not create the new instance {0}.", bbe.ToString ())); + case "CMSampleBuffer": + var pixelBuffer = new CVPixelBuffer (20, 10, CVPixelFormatType.CV24RGB); + + CMFormatDescriptionError fde; + var desc = CMVideoFormatDescription.CreateForImageBuffer (pixelBuffer, out fde); + + var sampleTiming = new CMSampleTimingInfo (); + + CMSampleBufferError sbe; + var sb = CMSampleBuffer.CreateForImageBuffer (pixelBuffer, true, desc, sampleTiming, out sbe); + if (sbe == CMSampleBufferError.None) + return sb; + else + throw new InvalidOperationException (string.Format ("Could not create the new instance {0}.", sbe.ToString ())); + default: + throw new InvalidOperationException (string.Format ("Could not create the new instance for type {0}.", t.Name)); + } + } + + [Test] + // test that the tag classes DO support the attachments API. + public void CheckAttachments () + { + var types = CMClockType.Assembly.GetTypes () + .Where(t => CMAttachmentInterfaceType.IsAssignableFrom(t) && !t.IsInterface); + foreach (var t in types) { + ICMAttachmentBearer obj = GetInstance (t); + if (obj is NSObject) + continue; + Assert.That (obj.Handle, Is.Not.EqualTo (IntPtr.Zero), t.Name + ".Handle"); + using (var attch = new CFString ("myAttch")) { + var mode = CMAttachmentMode.ShouldNotPropagate; + CMAttachmentMode otherMode; + obj.SetAttachment ("key", attch, CMAttachmentMode.ShouldNotPropagate); + using (var otherAttch = obj.GetAttachment ("key", out otherMode)) { + obj.RemoveAllAttachments (); + Assert.AreEqual (mode, otherMode); + Assert.IsNotNull (otherAttch, "For type {0}", t.Name); + Assert.AreEqual (attch.ToString (), otherAttch.ToString (), "For type {0}", t.Name); + } + } + if (t is IDisposable) { + var disposable = obj as IDisposable; + disposable.Dispose (); + } + } + } + + [Test] + // test that the classes do not support the attachments API + public void CheckFailAttachments () + { + // get all tupes that are public, native object but not NSobjects or DispatchSources and that are not interfaces or abstract classes + var types = CMClockType.Assembly.GetTypes () + .Where(t => !t.IsNotPublic && !CMAttachmentInterfaceType.IsAssignableFrom(t) + && NativeObjectInterfaceType.IsAssignableFrom (t) && !t.IsSubclassOf (NSObjectType) + && !t.IsSubclassOf (DispatchSourceType) && !t.IsInterface && !t.IsAbstract); + foreach (var t in types) { + if (Skip (t)) + continue; + var obj = new AttachableNativeObject (GetINativeInstance (t)); + Assert.That (obj.Handle, Is.Not.EqualTo (IntPtr.Zero), t.Name + ".Handle"); + using (var attch = new CFString ("myAttch")) { + CMAttachmentMode otherMode; + obj.SetAttachment ("key", attch, CMAttachmentMode.ShouldNotPropagate); + using (var otherAttch = obj.GetAttachment ("key", out otherMode)) { + obj.RemoveAllAttachments (); + Assert.Null (otherAttch, "For type {0}", t.Name); + } + } + if (t is IDisposable) { + var disposable = obj as IDisposable; + disposable.Dispose (); + } + } + } + } +} + +#endif // !__WATCHOS__ diff --git a/tests/introspection/ApiClassPtrTest.cs b/tests/introspection/ApiClassPtrTest.cs new file mode 100644 index 000000000000..2e58dea99372 --- /dev/null +++ b/tests/introspection/ApiClassPtrTest.cs @@ -0,0 +1,119 @@ +// +// Test fixture for class_ptr introspection tests +// +// Authors: +// Alex Soto +// +// Copyright 2012-2014, 2016 Xamarin Inc. +// +using System; +using System.Reflection; +using System.Linq; + +using NUnit.Framework; +using Xamarin.Utils; +using System.Runtime.CompilerServices; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + + public abstract class ApiClassPtrTest : ApiBaseTest { + + protected virtual bool Skip (Type type) + { + // skip delegate (and other protocol references) + foreach (object ca in type.GetCustomAttributes (false)) { + if (ca is ProtocolAttribute) + return true; + if (ca is ModelAttribute) + return true; + } + return SkipDueToAttribute (type); + } + + Type GetExtendedType (Type extensionType) + { + var method = + (from m in extensionType.GetMethods (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + where m.IsDefined (typeof (ExtensionAttribute), false) + select m).FirstOrDefault(); + + if (method != null) { + var paramType = method.GetParameters () [0].ParameterType; + if (paramType.Name == "String") + return typeof (NSString); + else + return paramType; + } + else + return null; + } + + IntPtr GetClassPtrFromRegister (Type t) + { + var attribs = t.GetCustomAttributes (typeof (RegisterAttribute), true); + if (attribs.Length > 0) { + var register = ((RegisterAttribute) attribs [0]); + return Class.GetHandle (register.Name); + } + return IntPtr.Zero; + } + + [Test] + public void VerifyClassPtr () + { + foreach (Type t in Assembly.GetTypes ()) { + if (t.IsNested || !NSObjectType.IsAssignableFrom (t)) + continue; + + if (t.ContainsGenericParameters) + continue; + + if (Skip (t)) + continue; + + FieldInfo fi = t.GetField ("class_ptr", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + if (fi == null) + continue; + IntPtr class_ptr = (IntPtr) fi.GetValue (null); + IntPtr register_class_ptr = GetClassPtrFromRegister (t); + + Assert.AreEqual (class_ptr, register_class_ptr, "class_ptr and RegisterAttribute are different: " + t.Name); + } + } + + [Test] + public void VerifyClassPtrCategories () + { + foreach (Type t in Assembly.GetTypes().Where (t => t.IsClass && t.IsSealed && t.IsAbstract)) { + if (Skip (t)) + continue; + + FieldInfo fi = t.GetField ("class_ptr", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + if (fi == null) + continue; + IntPtr class_ptr = (IntPtr)fi.GetValue (null); + + var extendedType = GetExtendedType (t); + IntPtr extended_class_ptr; + if (extendedType == null) + extended_class_ptr = IntPtr.Zero; + else + extended_class_ptr = GetClassPtrFromRegister (extendedType); + + Assert.AreEqual (class_ptr, extended_class_ptr, "class_ptr and RegisterAttribute from extended class are different: " + t.Name); + } + } + } +} + diff --git a/tests/introspection/ApiCoreImageFiltersTest.cs b/tests/introspection/ApiCoreImageFiltersTest.cs new file mode 100644 index 000000000000..fd7678e30cf6 --- /dev/null +++ b/tests/introspection/ApiCoreImageFiltersTest.cs @@ -0,0 +1,211 @@ +// +// Test the generated API for all CoreImage filters +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2013, 2015 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if !__WATCHOS__ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using CoreImage; +using Foundation; +using ObjCRuntime; +#if !MONOMAC +using UIKit; +#endif +#elif MONOMAC +using MonoMac.CoreImage; +using MonoMac.Foundation; +#else +using MonoTouch.CoreImage; +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +using MonoTouch.UIKit; +#endif + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public abstract class ApiCoreImageFiltersTest : ApiBaseTest { + + static Type CIFilterType = typeof (CIFilter); + + protected virtual bool Skip (Type type) + { + return Skip (type.Name) || SkipDueToAttribute (type); + } + + protected virtual bool Skip (string nativeName) + { + switch (nativeName) { + // Both reported in radar #21548819 + // NSUnknownKeyException [ valueForUndefinedKey:]: this class is not key value coding-compliant for the key inputPoint2. + case "CIDepthOfField": + // NSUnknownKeyException [ valueForUndefinedKey:]: this class is not key value coding-compliant for the key inputCropAmount. + case "CISunbeamsGenerator": + return true; + // FIXME: Remove if fixed. Doesn't appear to exist in El Capitan. Reported in radar #22099780 +// case "CIMaskedVariableBlur": +// cd .. return true; + default: + return false; + } + } + + [Test] + // this test checks that all native filters have a managed peer, i.e. against missing filters + public void CheckNativeFilters () + { + List filters = new List (); + int n = 0; + string qname = CIFilterType.AssemblyQualifiedName; + // that will give us only the list of filters supported by the executing version of iOS + foreach (var filter_name in CIFilter.FilterNamesInCategories (null)) { + if (Skip (filter_name)) + continue; + string type_name = qname.Replace ("CIFilter", filter_name); + if (Type.GetType (type_name, false, true) == null) { + filters.Add (filter_name); + // uncomment to generate bindings for any new native filter +// GenerateBinding (CIFilter.FromName (filter_name), Console.Out); + } + n++; + } + Assert.That (filters.Count, Is.EqualTo (0), "{0} native filters missing: {1}", filters.Count, String.Join (", ", filters)); + } + + [Test] + // this test checks that all managed filters have a native peer, i.e. against extra filters + public void CheckManagedFilters () + { + List filters = new List (CIFilter.FilterNamesInCategories (null)); + var nspace = CIFilterType.Namespace; + var types = CIFilterType.Assembly.GetTypes (); + foreach (Type t in types) { + if (t.Namespace != nspace) + continue; + + if (t.IsAbstract || !CIFilterType.IsAssignableFrom (t)) + continue; + + // we need to skip the filters that are not supported by the executing version of iOS + if (Skip (t)) + continue; + + var ctor = t.GetConstructor (Type.EmptyTypes); + if ((ctor == null) || ctor.IsAbstract) + continue; + + NSObject obj = ctor.Invoke (null) as NSObject; + Assert.That (obj.Handle, Is.Not.EqualTo (IntPtr.Zero), t.Name + ".Handle"); +#if false + // check base type - we might have our own base type or different names, so it's debug only (not failure) + var super = new Class (obj.Class.SuperClass).Name; + var bt = t.BaseType.Name; + if ((super != bt) && (bt == "CIFilter")) // check if we should (like Apple) use a non-default base type for filters + Console.WriteLine ("[WARN] {0}.SuperClass == {1} (native) and {2} managed", t.Name, super, bt); +#endif + int result = filters.RemoveAll (s => StringComparer.OrdinalIgnoreCase.Compare (t.Name, s) == 0); + Assert.That (result, Is.GreaterThan (0), t.Name); + } + // in case it's a buggy filter we need to try to remove it from the list too + for (int i = filters.Count - 1; i >= 0; i--) { + if (Skip (filters [i])) + filters.RemoveAt (i); + } + Assert.That (filters.Count, Is.EqualTo (0), "Managed filters not found for {0}", String.Join (", ", filters)); + } + + static void GenerateBinding (NSObject filter, TextWriter writer) + { + NSObject value; + var attributes = (filter as CIFilter).Attributes; + + writer.WriteLine ("[CoreImageFilter]"); + + if (!attributes.TryGetValue ((NSString)"CIAttributeFilterAvailable_iOS", out value)) { + writer.WriteLine ("[NoiOS]"); + } else { + var v = value.ToString (); + // in the (quite common) case we get "5" for iOS 5.0 + if (v.IndexOf ('.') == -1) + v += ".0"; + var ios = Version.Parse (v); + // we only document availability for iOS 6+ + if (ios.Major > 5) + writer.WriteLine ("[iOS ({0},{1})]", ios.Major, ios.Minor); + } + + if (!attributes.TryGetValue ((NSString)"CIAttributeFilterAvailable_Mac", out value)) { + writer.WriteLine ("[NoMac]"); + } else { + try { + var mac = Version.Parse (value.ToString ()); + // we only document availability for 10.7+ + if (mac.Minor > 6) + writer.WriteLine ("[Mac ({0},{1})]", mac.Major, mac.Minor); + } + catch (FormatException) { + // 10.? is not a valid version - we'll assume it was added a long time ago (in a galaxy far away) + writer.WriteLine ("// incorrect version string for OSX: '{0}' Double-check documentation", value); + } + } + writer.WriteLine ("[BaseType (typeof (CIFilter))]"); + var fname = attributes [(NSString)"CIAttributeFilterName"].ToString (); + writer.WriteLine ("interface {0} {{", fname); + foreach (var k in attributes.Keys) { + var key = k.ToString (); + if (key.StartsWith ("CIAttribute", StringComparison.Ordinal)) + continue; + // CIFilter defines it for all filters + if (key == "inputImage") + continue; + + writer.WriteLine (); + var dict = attributes [k] as NSDictionary; + var type = dict [(NSString) "CIAttributeClass"]; + writer.WriteLine ("\t[CoreImageProperty (\"{0}\")]", key); + + // by default we drop the "input" prefix, but keep the "output" prefix to avoid confusion + if (key.StartsWith ("input", StringComparison.Ordinal)) + key = Char.ToUpperInvariant (key [5]) + key.Substring (6); + + var ptype = type.ToString (); + // Too many things ends up in NSNumber but we do a better job in our bindings + if (ptype == "NSNumber") { + ptype = "float"; + writer.WriteLine ("\t// TODO: this was an NSNumber transformed to float, but maybe an int or bool is more appropriate"); + } + writer.WriteLine ("\t{0} {1} {{ get; set; }}", ptype, key); + } + writer.WriteLine ("}"); + writer.WriteLine (); + } + } +} + +#endif // !__WATCHOS__ diff --git a/tests/introspection/ApiCtorInitTest.cs b/tests/introspection/ApiCtorInitTest.cs new file mode 100644 index 000000000000..8c9564abc7ea --- /dev/null +++ b/tests/introspection/ApiCtorInitTest.cs @@ -0,0 +1,306 @@ +// +// Test the generated API `init` selectors are usable by the binding consumers +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2015 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Reflection; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + + public abstract class ApiCtorInitTest : ApiBaseTest { + + string instance_type_name; + + /// + /// Gets or sets a value indicating whether this test fixture will log untested types. + /// + /// true if log untested types; otherwise, false. + public bool LogUntestedTypes { get; set; } + + /// + /// Override this method if you want the test to skip some specific types. + /// By default types decorated with [Model] will be skipped. + /// + /// The Type to be tested + protected virtual bool Skip (Type type) + { + if (type.ContainsGenericParameters) + return true; + + // skip delegate (and other protocol references) + foreach (object ca in type.GetCustomAttributes (false)) { + if (ca is ProtocolAttribute) + return true; + if (ca is ModelAttribute) + return true; + } + switch (type.Name) { +#if !XAMCORE_2_0 + case "AVAssetResourceLoader": // We have DisableDefaultCtor in XAMCORE_2_0 but can't change in compat because of backwards compat + case "AVAssetResourceLoadingRequest": + case "AVAssetResourceLoadingContentInformationRequest": +#endif + // on iOS 8.2 (beta 1) we get: NSInvalidArgumentException Caller did not provide an activityType, and this process does not have a NSUserActivityTypes in its Info.plist. + // even if we specify an NSUserActivityTypes in the Info.plist - might be a bug or there's a new (undocumented) requirement + case "NSUserActivity": + return true; + } + return SkipDueToAttribute (type); + } + + /// + /// Checks that the Handle property of the specified NSObject instance is not null (not IntPtr.Zero). + /// + /// NSObject instance to validate + protected virtual void CheckHandle (NSObject obj) + { + if (obj.Handle == IntPtr.Zero) + ReportError ("{0} : Handle", instance_type_name); + } + + /// + /// Checks that ToString does not return null (not helpful for debugging) and that it does not crash. + /// + /// NSObject instance to validate + protected virtual void CheckToString (NSObject obj) + { + if (obj.ToString () == null) + ReportError ("{0} : ToString", instance_type_name); + } + + bool GetIsDirectBinding (NSObject obj) + { +#if XAMCORE_2_0 + int flags = (byte) typeof (NSObject).GetField ("flags", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic).GetValue (obj); + return (flags & 4) == 4; +#else + return (bool) typeof (NSObject).GetField ("IsDirectBinding", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic).GetValue (obj); +#endif + } + + /// + /// Checks that the IsDirectBinding property is identical to the IsWrapper property of the Register attribute. + /// + /// Object. + protected virtual void CheckIsDirectBinding (NSObject obj) + { + var attrib = obj.GetType ().GetCustomAttribute (false); + // only check types that we register - that way we avoid the 118 MonoTouch.CoreImagge.CI* "special" types + if (attrib == null) + return; + var is_wrapper = attrib != null && attrib.IsWrapper; + var is_direct_binding = GetIsDirectBinding (obj); + if (is_direct_binding != is_wrapper) + ReportError ("{0} : IsDirectBinding (expected {1}, got {2})", instance_type_name, is_wrapper, is_direct_binding); + } + + /// + /// Skip, or not, the specified pproperty from being verified. + /// + /// PropertyInfo candidate + protected virtual bool Skip (PropertyInfo pi) + { + // manually bound API can have the attributes only on the property (and not on the getter/setter) + return SkipDueToAttribute (pi); + } + + /// + /// Dispose the specified NSObject instance. In some cases objects cannot be disposed safely. + /// Override this method to keep them alive while the remaining tests execute. + /// + /// NSObject instance to dispose + /// Type of the object, to be used if special logic is required. + protected virtual void Dispose (NSObject obj, Type type) + { + obj.Dispose (); + } + + protected virtual void CheckNSObjectProtocol (NSObject obj) + { + // not documented to allow null, but commonly used this way. OTOH it's not clear what code answer this + // (it might be different implementations) but we can make sure that Apple allows null with this test + // ref: https://bugzilla.xamarin.com/show_bug.cgi?id=35924 + var kind_of_null = obj.IsKindOfClass (null); + if (kind_of_null) + ReportError ("{0} : IsKindOfClass(null) failed", instance_type_name); + var is_member_of_null = obj.IsMemberOfClass (null); + if (is_member_of_null) + ReportError ("{0} : IsMemberOfClass(null) failed", instance_type_name); + var respond_to_null = obj.RespondsToSelector (null); + if (respond_to_null) + ReportError ("{0} : RespondToSelector(null) failed", instance_type_name); + var conforms_to_null = obj.ConformsToProtocol (IntPtr.Zero); + if (conforms_to_null) + ReportError ("{0} : ConformsToProtocol(null) failed", instance_type_name); + } + + // if a .ctor is obsolete then it's because it was not usable (nor testable) + protected override bool SkipDueToAttribute (MemberInfo member) + { + if (member == null) + return false; + var ca = member.GetCustomAttribute (); + return ca != null || base.SkipDueToAttribute (member); + } + + [Test] + public void DefaultCtorAllowed () + { + Errors = 0; + int n = 0; + + foreach (Type t in Assembly.GetTypes ()) { + if (t.IsAbstract || !NSObjectType.IsAssignableFrom (t)) + continue; + + if (Skip (t)) + continue; + + var ctor = t.GetConstructor (Type.EmptyTypes); + if (SkipDueToAttribute (ctor)) + continue; + + if ((ctor == null) || ctor.IsAbstract) { + if (LogUntestedTypes) + Console.WriteLine ("[WARNING] {0} was skipped because it had no default constructor", t); + continue; + } + + instance_type_name = t.FullName; + if (LogProgress) + Console.WriteLine ("{0}. {1}", n, instance_type_name); + + NSObject obj = null; + try { + obj = ctor.Invoke (null) as NSObject; + CheckHandle (obj); + CheckToString (obj); + CheckIsDirectBinding (obj); + CheckNSObjectProtocol (obj); + Dispose (obj, t); + } + catch (Exception e) { + // Objective-C exception thrown + if (!ContinueOnFailure) + throw; + + TargetInvocationException tie = (e as TargetInvocationException); + if (tie != null) + e = tie.InnerException; + ReportError ("Default constructor not allowed for {0} : {1}", instance_type_name, e.Message); + } + n++; + } + Assert.AreEqual (0, Errors, "{0} potential errors found in {1} default ctor validated", Errors, n); + } + + // .NET constructors are not virtual, so we need to re-expose the base class .ctor when a subclass is created. + // That's very important for designated initializer since we can end up with no correct/safe way to create + // subclasses of an existing type + [Test] + public void DesignatedInitializer () + { + Errors = 0; + int n = 0; + + foreach (Type t in Assembly.GetTypes ()) { + // we only care for NSObject subclasses that we expose publicly + if (!t.IsPublic || !NSObjectType.IsAssignableFrom (t)) + continue; + + int designated = 0; + foreach (var ctor in t.GetConstructors ()) { + if (ctor.GetCustomAttribute () == null) + continue; + designated++; + } + // that does not mean that inlining is not required, i.e. it might be useful, even needed + // but it's not a showstopper for subclassing so we'll start with those cases + if (designated > 1) + continue; + + var base_class = t.BaseType; + // NSObject ctor requirements are handled by the generator + if (base_class == NSObjectType) + continue; + foreach (var ctor in base_class.GetConstructors ()) { + // if the base ctor is a designated (not a convenience) initializer then we should re-expose it + if (ctor.GetCustomAttribute () == null) + continue; + + // check if this ctor (from base type) is exposed in the current (subclass) type + if (!Match (ctor, t)) + ReportError ("{0} should re-expose {1}::{2}", t, base_class.Name, ctor.ToString ().Replace ("Void ", String.Empty)); + n++; + } + } + Assert.AreEqual (0, Errors, "{0} potential errors found in {1} designated initializer validated", Errors, n); + } + + protected virtual bool Match (ConstructorInfo ctor, Type type) + { + switch (type.Name) { + case "MKTileOverlayRenderer": + // NSInvalidArgumentEception Expected a MKTileOverlay + // looks like Apple has not yet added a DI for this type, but it should be `initWithTileOverlay:` + if (ctor.ToString () == "Void .ctor(IMKOverlay)") + return true; + break; + case "MPSImageHistogram": + // Could not initialize an instance of the type 'MetalPerformanceShaders.MPSImageHistogram': the native 'initWithDevice:' method returned nil. + // make sense: there's a `initWithDevice:histogramInfo:` DI + if (ctor.ToString () == "Void .ctor(IMTLDevice)") + return true; + break; + case "NSDataDetector": + // -[NSDataDetector initWithPattern:options:error:]: Not valid for NSDataDetector + if (ctor.ToString () == "Void .ctor(NSString, NSRegularExpressionOptions, NSError&)") + return true; + break; +#if __TVOS__ + case "UISearchBar": + // - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER __TVOS_PROHIBITED; + return true; +#endif + } + + var expected = ctor.ToString (); + // NonPublic to get `protected` which can be autogenerated for abstract types (subclassing a non-abstract type) + foreach (var candidate in type.GetConstructors (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { + if (candidate.ToString () == expected) + return true; + } + return false; + } + } +} diff --git a/tests/introspection/ApiFieldTest.cs b/tests/introspection/ApiFieldTest.cs new file mode 100644 index 000000000000..88b7cad97fd2 --- /dev/null +++ b/tests/introspection/ApiFieldTest.cs @@ -0,0 +1,187 @@ +// +// Test the generated API fields (e.g. against typos or unexisting values for the platform) +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2014 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.IO; +using System.Collections.Generic; +using System.Reflection; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + + [Preserve (AllMembers = true)] + public abstract class ApiFieldTest : ApiBaseTest { +#if XAMCORE_2_0 + const string NSStringType = "Foundation.NSString"; +#elif MONOMAC + const string NSStringType = "MonoMac.Foundation.NSString"; +#else + const string NSStringType = "MonoTouch.Foundation.NSString"; +#endif + + /// + /// Override if you want to skip testing the specified type. + /// + /// Type to be tested + protected virtual bool Skip (Type type) + { + return false; + } + + /// + /// Override if you want to skip testing the specified property. + /// + /// Property to be tested + protected virtual bool Skip (PropertyInfo property) + { + return SkipDueToAttribute (property); + } + + /// + /// Override if you want to skip testing the specified constant. + /// + /// Constant name to ignore. + protected virtual bool Skip (string constantName) + { + return false; + } + + // check generated code, which are static properties, e.g. + // [Field ("kCGImagePropertyIPTCObjectTypeReference")] + // NSString IPTCObjectTypeReference { get; } + bool CheckAgainstNull (PropertyInfo p, out string name) + { + name = String.Empty; + var g = p.GetGetMethod (true); + if (!g.IsStatic) + return true; + + if (Skip (p)) + return true; + + try { + // if it return nulls then it could be a typo... + // or something not available in the executing version of iOS + bool result = g.Invoke (null, null) != null; + if (!result) + name = p.DeclaringType.FullName + "." + p.Name; + return result; + } + catch (Exception e) { + Console.WriteLine ("[FAIL] Exception on '{0}' : {1}", p, e); + name = p.DeclaringType.FullName + "." + p.Name; + return false; + } + } + + [Test] + public void NonNullNSStringFields () + { + var failed_fields = new List (); + + Errors = 0; + int c = 0, n = 0; + foreach (Type t in Assembly.GetTypes ()) { + if (Skip (t) || SkipDueToAttribute (t)) + continue; + + if (LogProgress) + Console.WriteLine ("{0}. {1}", c++, t.FullName); + + foreach (var p in t.GetProperties (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) { + // looking for properties with getters only + if (p.CanWrite || !p.CanRead) + continue; + + if (p.PropertyType.FullName != NSStringType) + continue; + + if (SkipDueToAttribute (p)) + continue; + + string name; + bool result = CheckAgainstNull (p, out name); + if (!result) { + ReportError (name); + failed_fields.Add (name); + } + n++; + } + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} fields validated: {2}", Errors, n, string.Join (", ", failed_fields)); + } + + [Test] + public void FieldExists () + { + var failed_fields = new List (); + + Errors = 0; + int c = 0, n = 0; + foreach (Type t in Assembly.GetTypes ()) { + if (Skip (t) || SkipDueToAttribute (t)) + continue; + + if (LogProgress) + Console.WriteLine ("{0}. {1}", c++, t.FullName); + + foreach (var p in t.GetProperties (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) { + // looking for properties with getters only + if (p.CanWrite || !p.CanRead) + continue; + + if (SkipDueToAttribute (p)) + continue; + + var f = p.GetCustomAttribute (); + if (f == null) + continue; + + string name = f.SymbolName; + if (Skip (name)) + continue; + + string path = FindLibrary (f.LibraryName); + IntPtr lib = Dlfcn.dlopen (path, 0); + if (Dlfcn.GetIndirect (lib, name) == IntPtr.Zero) { + ReportError ("Could not find the field '{0}' in {1}", name, path); + failed_fields.Add (name); + } + Dlfcn.dlclose (lib); + n++; + } + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} fields validated: {2}", Errors, n, string.Join (", ", failed_fields)); + } + } +} diff --git a/tests/introspection/ApiPInvokeTest.cs b/tests/introspection/ApiPInvokeTest.cs new file mode 100644 index 000000000000..6e587237bf15 --- /dev/null +++ b/tests/introspection/ApiPInvokeTest.cs @@ -0,0 +1,251 @@ +// +// ApiPInvokeTest.cs: enforce P/Invoke signatures +// +// Authors: +// Aaron Bockover +// Sebastien Pouliot +// +// Copyright 2013-2014 Xamarin, Inc. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using ObjCRuntime; +using Foundation; +#elif MONOMAC +using MonoMac.ObjCRuntime; +using MonoMac.Foundation; +#else +using MonoTouch.ObjCRuntime; +using MonoTouch.Foundation; +#endif + +namespace Introspection +{ + [Preserve (AllMembers = true)] + public abstract class ApiPInvokeTest : ApiBaseTest { + IEnumerable pinvokeQuery; + + public ApiPInvokeTest () + { + ContinueOnFailure = true; + LogProgress = false; + + pinvokeQuery = from type in Assembly.GetTypes () + where !Skip (type) + from mi in type.GetMethods ( + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.Static) + let attr = mi.GetCustomAttribute () + where attr != null && !Skip (mi) + select mi; + } + + protected virtual bool Skip (Type type) + { + return SkipDueToAttribute (type); + } + + protected virtual bool Skip (MethodInfo methodInfo) + { + return SkipDueToAttribute (methodInfo); + } + + [Test] + public void Signatures () + { + int totalPInvokes = 0; + int totalErrors = 0; + + foreach (MethodInfo mi in pinvokeQuery) { + totalPInvokes++; + if (!CheckSignature (mi)) { + totalErrors++; + + if (!ContinueOnFailure) + break; + } + } + + AssertIfErrors ( + "{0} errors found in {1} P/Invoke signatures validated", + totalErrors, totalPInvokes); + } + + protected virtual bool CheckSignature (MethodInfo mi) + { + var success = true; + + if (!CheckReturnParameter (mi, mi.ReturnParameter)) + success = false; + + foreach (var pi in mi.GetParameters ()) { + if (!CheckParameter (mi, pi)) + success = false; + } + + return success; + } + + protected virtual bool CheckReturnParameter (MethodInfo mi, ParameterInfo pi) + { + return CheckForEnumParameter (mi, pi); + } + + protected virtual bool CheckParameter (MethodInfo mi, ParameterInfo pi) + { + return CheckForEnumParameter (mi, pi); + } + + protected virtual bool CheckForEnumParameter (MethodInfo mi, ParameterInfo pi) + { + if (pi.ParameterType.IsEnum && pi.ParameterType.GetCustomAttribute () != null) { + AddErrorLine ("{0}.{1} has a [Native] enum parameter in its signature: {2} {3}", + mi.DeclaringType.FullName, mi.Name, pi.ParameterType, pi.Name); + return false; + } + + return true; + } + + protected virtual bool Skip (string symbolName) + { + return false; + } + + protected virtual bool SkipLibrary (string libraryName) + { + return false; + } + + [Test] + public void SymbolExists () + { + var failed_api = new List (); + Errors = 0; + int c = 0, n = 0; + foreach (MethodInfo mi in pinvokeQuery) { + + if (LogProgress) + Console.WriteLine ("{0}. {1}", c++, mi); + + var dllimport = mi.GetCustomAttribute (); + + string libname = dllimport.Value; + if (libname == "__Internal" || SkipLibrary (libname)) + continue; + + string path = FindLibrary (dllimport.Value, requiresFullPath: true); + + string name = dllimport.EntryPoint ?? mi.Name; + if (Skip (name)) + continue; + + IntPtr lib = Dlfcn.dlopen (path, 0); + if (Dlfcn.GetIndirect (lib, name) == IntPtr.Zero) { + ReportError ("Could not find the field '{0}' in {1}", name, path); + failed_api.Add (name); + } + Dlfcn.dlclose (lib); + n++; + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} functions validated: {2}", Errors, n, string.Join (", ", failed_api)); + } + + // we just want to confirm the symbol exists so `dlsym` can be disabled + protected void Check (Assembly a) + { + Errors = 0; + int n = 0; + foreach (var t in a.GetTypes ()) { + foreach (var m in t.GetMethods (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { + if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) + continue; + + var dllimport = m.GetCustomAttribute (); + + string name = dllimport.EntryPoint ?? m.Name; + switch (name) { + // known not to be present in ARM64 + case "objc_msgSend_stret": + case "objc_msgSendSuper_stret": + // the linker normally removes them (IntPtr.Size optimization) + continue; + } + + string path = dllimport.Value; + switch (path) { + case "__Internal": + // load from executable + path = null; + break; + case "libc": + // we still have some rogue/not-fully-qualified DllImport + path = "/usr/lib/libSystem.dylib"; + break; + } + + var lib = Dlfcn.dlopen (path, 0); + var h = Dlfcn.dlsym (lib, name); + if (h == IntPtr.Zero) + ReportError ("Could not find the symbol '{0}' in {1}", name, path); + Dlfcn.dlclose (lib); + n++; + } + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} symbol lookups", Errors, n); + } + + protected abstract bool SkipAssembly (Assembly a); + + // Note: this looks very similar to the "SymbolExists" test above (and it is) + // except that we never skip based on availability attributes or __Internal... + // since this is a test to ensure thigns will work at native link time (e.g. + // for devices) when dlsym is disabled + + [Test] + public void Product () + { + var a = typeof (NSObject).Assembly; + if (!SkipAssembly (a)) + Check (a); + } + + // since we already have non-linked version of the most common assemblies available here + // we can use them to check for missing symbols (from DllImport) + // it's not complete (there's many more SDK assemblies) but we cannot add all of them into a single project anyway + + [Test] + public void Corlib () + { + var a = typeof (int).Assembly; + if (!SkipAssembly (a)) + Check (a); + } + + [Test] + public void System () + { + var a = typeof (System.Net.WebClient).Assembly; + if (!SkipAssembly (a)) + Check (a); + } + + [Test] + public void SystemCore () + { + var a = typeof (Enumerable).Assembly; + if (!SkipAssembly (a)) + Check (a); + } + } +} diff --git a/tests/introspection/ApiProtocolTest.cs b/tests/introspection/ApiProtocolTest.cs new file mode 100644 index 000000000000..487a11141975 --- /dev/null +++ b/tests/introspection/ApiProtocolTest.cs @@ -0,0 +1,297 @@ +// +// Test the generated API for common protocol support +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2013, 2015 Xamarin Inc. +// + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + + public abstract class ApiProtocolTest : ApiBaseTest { + + static IntPtr conform_to = Selector.GetHandle ("conformsToProtocol:"); + + public ApiProtocolTest () + { + ContinueOnFailure = true; + } + + static bool ConformTo (IntPtr klass, IntPtr protocol) + { + return bool_objc_msgSend_IntPtr (klass, conform_to, protocol); + } + + protected virtual bool Skip (Type type) + { + switch (type.Name) { + // *** NSForwarding: warning: object 0x5cbd078 of class 'JSExport' does not implement methodSignatureForSelector: -- trouble ahead + // *** NSForwarding: warning: object 0x5cbd078 of class 'JSExport' does not implement doesNotRecognizeSelector: -- abort + case "JSExport": + return true; + default: +#if !XAMCORE_2_0 + // in Classic our internal delegates _inherits_ the type with the [Protocol] attribute + // in Unified our internal delegates _implements_ the interface that has the [Protocol] attribute + if (type.GetCustomAttribute (true) != null) + return true; +#endif + return SkipDueToAttribute (type); + } + } + + IntPtr GetClass (Type type) + { + return Class.GetHandle (type); + } + + protected virtual bool Skip (Type type, string protocolName) + { + switch (protocolName) { + case "NSCopying": + switch (type.Name) { + // undocumented conformance (up to 7.0) and conformity varies between iOS versions + case "CAEmitterCell": + case "GKAchievement": + case "GKScore": + // new in iOS8 and 10.0 + case "NSExtensionContext": + return true; // skip + } + break; + case "NSCoding": + switch (type.Name) { + // only documented to support NSCopying - not NSCoding (fails on iOS 7.1 but not 8.0) + case "NSUrlSessionTask": + case "NSUrlSessionDataTask": + case "NSUrlSessionUploadTask": + case "NSUrlSessionDownloadTask": + // + case "NSUrlSessionConfiguration": + case "NSMergeConflict": + // new in iOS8 and 10.0 + case "NSExtensionContext": + case "NSItemProvider": + // undocumented + return true; + } + break; + case "NSSecureCoding": + switch (type.Name) { + case "NSMergeConflict": // undocumented + // only documented to support NSCopying (and OSX side only does that) + case "NSUrlSessionTask": + case "NSUrlSessionDataTask": + case "NSUrlSessionUploadTask": + case "NSUrlSessionDownloadTask": + case "NSUrlSessionConfiguration": + // new in iOS8 and 10.0 + case "NSExtensionContext": + case "NSItemProvider": + case "NSParagraphStyle": //17770106 + case "NSMutableParagraphStyle": //17770106 + return true; // skip + // iOS9 / 10.11 + case "NSPersonNameComponentsFormatter": + return true; // skip + } + break; + } + return false; + } + + void CheckProtocol (string protocolName, Action action) + { + IntPtr protocol = Runtime.GetProtocol (protocolName); + Assert.AreNotEqual (protocol, IntPtr.Zero, protocolName); + + int n = 0; + foreach (Type t in Assembly.GetTypes ()) { + if (!NSObjectType.IsAssignableFrom (t)) + continue; + + if (Skip (t) || Skip (t, protocolName)) + continue; + + if (LogProgress) + Console.WriteLine ("{0}. {1} conforms to {2}", ++n, t.FullName, protocolName); + + IntPtr klass = GetClass (t); + action (t, klass, ConformTo (klass, protocol)); + } + } + + [Test] + public void Coding () + { + Errors = 0; + CheckProtocol ("NSCoding", delegate (Type type, IntPtr klass, bool result) { + if (result) { + // `type` conforms to (native) NSCoding so... + if (result) { + // the type should implements INSCoding + if (!typeof (INSCoding).IsAssignableFrom (type)) { + ReportError ("{0} conforms to NSCoding but does not implement INSCoding", type.Name); + } + // FIXME: and implement the .ctor(NSCoder) + } + } + }); + Assert.AreEqual (Errors, 0, "{0} types conforms to NSCoding but does not implement INSCoding", Errors); + } + + // [Test] -> iOS 6.0+ and Mountain Lion (10.8) + + public virtual void SecureCoding () + { + Errors = 0; + CheckProtocol ("NSSecureCoding", delegate (Type type, IntPtr klass, bool result) { + if (result) { + // the type should implements INSSecureCoding + if (!typeof (INSSecureCoding).IsAssignableFrom (type)) { + ReportError ("{0} conforms to NSSecureCoding but does not implement INSSecureCoding", type.Name); + } + } + }); + Assert.AreEqual (Errors, 0, "{0} types conforms to NSSecureCoding but does not implement INSSecureCoding", Errors); + } + + bool SupportsSecureCoding (Type type) + { + Class cls = new Class (type); + if (!bool_objc_msgSend_IntPtr (cls.Handle, Selector.GetHandle ("respondsToSelector:"), Selector.GetHandle ("supportsSecureCoding"))) + return false; + + return NSSecureCoding.SupportsSecureCoding (type); + } + + + // [Test] -> iOS 6.0+ and Mountain Lion (10.8) + + public virtual void SupportsSecureCoding () + { + Errors = 0; + CheckProtocol ("NSSecureCoding", delegate (Type type, IntPtr klass, bool result) { + bool supports = SupportsSecureCoding (type); + if (result) { + // check that +supportsSecureCoding returns YES + if (!supports) { + ReportError ("{0} conforms to NSSecureCoding but SupportsSecureCoding returned false", type.Name); + } + } else if (type.IsPublic && supports) { + // there are internal types, e.g. DataWrapper : NSData, that subclass NSSecureCoding-types without + // [re-]declaring their allegiance - but we can live with those small betrayals + Assert.IsFalse (NSSecureCoding.SupportsSecureCoding (type), "{0} !SupportsSecureCoding", type.Name); + ReportError ("SupportsSecureCoding returns true but {0} does not conforms to NSSecureCoding", type.Name); + } + }); + Assert.AreEqual (Errors, 0, "{0} types conforms to NSCoding but does not implement INSSecureCoding", Errors); + } + + [Test] + public void Copying () + { + Errors = 0; + CheckProtocol ("NSCopying", delegate (Type type, IntPtr klass, bool result) { + // `type` conforms to (native) NSCopying so... + if (result) { + // the type should implements INSCopying + if (!typeof (INSCopying).IsAssignableFrom (type)) { + ReportError ("{0} conforms to NSCopying but does not implement INSCopying", type.Name); + } + } + }); + Assert.AreEqual (Errors, 0, "{0} types conforms to NSCopying but does not implement INSCopying", Errors); + } + + [Test] + public void MutableCopying () + { + Errors = 0; + CheckProtocol ("NSMutableCopying", delegate (Type type, IntPtr klass, bool result) { + // `type` conforms to (native) NSMutableCopying so... + if (result) { + // the type should implements INSMutableCopying + if (!typeof (INSMutableCopying).IsAssignableFrom (type)) { + ReportError ("{0} conforms to NSMutableCopying but does not implement INSMutableCopying", type.Name); + } + } + }); + Assert.AreEqual (Errors, 0, "{0} types conforms to NSMutableCopying but does not implement INSMutableCopying", Errors); + } + + [Test] + public void GeneralCase () + { + Errors = 0; + foreach (Type t in Assembly.GetTypes ()) { + if (!NSObjectType.IsAssignableFrom (t)) + continue; + + if (Skip (t)) + continue; + + foreach (var intf in t.GetInterfaces ()) { + if (SkipDueToAttribute (intf)) + continue; + + string protocolName = intf.Name.Substring (1); + switch (protocolName) { + case "NSCoding": + case "NSSecureCoding": + case "NSCopying": + case "NSMutableCopying": + // we have special test cases for them + continue; + default: +#if !XAMCORE_2_0 + // in Classic our internal delegates _inherits_ the type with the [Protocol] attribute + // in Unified our internal delegates _implements_ the interface that has the [Protocol] attribute + var pt = Type.GetType (intf.Namespace + "." + protocolName + ", " + intf.Assembly.FullName); + if (SkipDueToAttribute (pt)) + continue; +#endif + if (Skip (t, protocolName)) + continue; + break; + } + + var a = intf.GetCustomAttribute (true); + if (a == null || a.IsInformal) + continue; + + IntPtr protocol = Runtime.GetProtocol (protocolName); + if (protocol == IntPtr.Zero) + continue; // not a protocol + + if (LogProgress) + Console.WriteLine ("{0} conforms to {1}", t.FullName, protocolName); + + var klass = new Class (t); + if (klass.Handle == IntPtr.Zero) { + AddErrorLine ("Could not load {0}", t.FullName); + } else if (t.IsPublic && !ConformTo (klass.Handle, protocol)) { + // note: some internal types, e.g. like UIAppearance subclasses, return false (and there's not much value in changing this) + ReportError ("Type {0} (native: {1}) does not conform {2}", t.FullName, klass.Name, protocolName); + } + } + } + AssertIfErrors ("{0} types do not really conform to the protocol interfaces", Errors); + } + } +} diff --git a/tests/introspection/ApiSelectorTest.cs b/tests/introspection/ApiSelectorTest.cs new file mode 100644 index 000000000000..5e85eb0cd933 --- /dev/null +++ b/tests/introspection/ApiSelectorTest.cs @@ -0,0 +1,406 @@ +// +// Test the generated API selectors against typos or non-existing cases +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Reflection; +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + + public abstract class ApiSelectorTest : ApiBaseTest { + + // not everything should be even tried + + protected virtual bool Skip (Type type) + { + if (type.ContainsGenericParameters) + return true; + + // skip delegate (and other protocol references) + foreach (object ca in type.GetCustomAttributes (false)) { + if (ca is ProtocolAttribute) + return true; + if (ca is ModelAttribute) + return true; + } + return SkipDueToAttribute (type); + } + + protected virtual bool Skip (Type type, string selectorName) + { +#if !XAMCORE_2_0 + // old binding mistake + if (selectorName == "subscribedCentrals") + return true; +#else + // The MapKit types/selectors are optional protocol members pulled in from MKAnnotation/MKOverlay. + // These concrete (wrapper) subclasses do not implement all of those optional members, but we + // still need to provide a binding for them, so that user subclasses can implement those members. + switch (type.Name) { + case "MKCircle": + case "MKPolygon": + case "MKPolyline": + switch (selectorName) { + case "canReplaceMapContent": + return true; + } + break; + case "MKShape": + switch (selectorName) { + case "setCoordinate:": + return true; + } + break; + case "MKPlacemark": + switch (selectorName) { + case "setCoordinate:": + case "subtitle": + return true; + } + break; + case "MKTileOverlay": + switch (selectorName) { + case "intersectsMapRect:": + return true; + } + break; + // AVAudioChannelLayout and AVAudioFormat started conforming to NSSecureCoding in OSX 10.11 and iOS 9 + case "AVAudioChannelLayout": + case "AVAudioFormat": + switch (selectorName) { + case "encodeWithCoder:": + return true; + } + break; + // SKTransition started conforming to NSCopying in OSX 10.11 and iOS 9 + case "SKTransition": + switch (selectorName) { + case "copyWithZone:": + return true; + } + break; + } +#endif + // This ctors needs to be manually bound + switch (type.Name) { + case "GKPath": + switch (selectorName) { + case "initWithPoints:count:radius:cyclical:": + return true; + } + break; + case "GKPolygonObstacle": + switch (selectorName) { + case "initWithPoints:count:": + return true; + } + break; + case "NSImage": + switch (selectorName) { + case "initByReferencingFile:": + return true; + } + break; + case "SKVideoNode": + switch (selectorName) { + case "initWithFileNamed:": + case "initWithURL:": + case "initWithVideoFileNamed:": + case "initWithVideoURL:": + case "videoNodeWithFileNamed:": + case "videoNodeWithURL:": + return true; + } + break; + } + + // old binding mistake + return (selectorName == "initWithCoder:"); + } + + protected virtual bool CheckResponse (bool value, Type actualType, MethodBase method, ref string name) + { + if (value) + return true; + + var mname = method.Name; + // properties getter and setter will be methods in the _Extensions type + if (method.IsSpecialName) + mname = mname.Replace ("get_", "Get").Replace ("set_", "Set"); + + // it's possible that the selector was inlined for an OPTIONAL protocol member + // we do not want those reported (too many false positives) and we have other tests to find such mistakes + foreach (var intf in actualType.GetInterfaces ()) { + if (intf.GetCustomAttributes () == null) + continue; + var ext = Type.GetType (intf.Namespace + "." + intf.Name.Remove (0, 1) + "_Extensions, " + intf.Assembly.FullName); + if (ext == null) + continue; + foreach (var m in ext.GetMethods ()) { + if (mname != m.Name) + continue; + var parameters = method.GetParameters (); + var ext_params = m.GetParameters (); + // first parameters is `this XXX This` + if (parameters.Length == ext_params.Length - 1) { + bool match = true; + for (int i = 1; i < ext_params.Length; i++) { + match |= (parameters [i - 1].ParameterType == ext_params [i].ParameterType); + } + if (match) + return true; + } + } + } + + name = actualType.FullName + " : " + name; + return false; + } + + static IntPtr responds_handle = Selector.GetHandle ("instancesRespondToSelector:"); + + [Test] + public void Protocols () + { + Errors = 0; + int n = 0; + + foreach (Type t in Assembly.GetTypes ()) { + if (t.IsNested || !NSObjectType.IsAssignableFrom (t)) + continue; + + foreach (object ca in t.GetCustomAttributes (false)) { + if (ca is ProtocolAttribute) { + foreach (var c in t.GetConstructors (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { + ProcessProtocolMember (t, c, ref n); + } + foreach (var m in t.GetMethods (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { + ProcessProtocolMember (t, m, ref n); + } + } + } + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} protocol selectors validated", Errors, n); + } + + void ProcessProtocolMember (Type t, MethodBase m, ref int n) + { + if (SkipDueToAttribute (m)) + return; + + foreach (object ca in m.GetCustomAttributes (true)) { + ExportAttribute export = (ca as ExportAttribute); + if (export == null) + continue; + + string name = export.Selector; + if (Skip (t, name)) + continue; + + CheckInit (t, m, name); + n++; + } + } + + protected virtual IntPtr GetClassForType (Type type) + { + var fi = type.GetField ("class_ptr", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + if (fi == null) + return IntPtr.Zero; // e.g. *Delegate + return (IntPtr) fi.GetValue (null); + } + + [Test] + public void InstanceMethods () + { + Errors = 0; + int n = 0; + + foreach (Type t in Assembly.GetTypes ()) { + if (t.IsNested || !NSObjectType.IsAssignableFrom (t)) + continue; + + if (Skip (t) || SkipDueToAttribute (t)) + continue; + + IntPtr class_ptr = GetClassForType (t); + + if (class_ptr == IntPtr.Zero) + continue; + + foreach (var c in t.GetConstructors (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { + Process (class_ptr, t, c, ref n); + } + + foreach (var m in t.GetMethods (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { + Process (class_ptr, t, m, ref n); + } + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} instance selector validated", Errors, n); + } + + void Process (IntPtr class_ptr, Type t, MethodBase m, ref int n) + { + if (m.DeclaringType != t || SkipDueToAttribute (m)) + return; + + foreach (object ca in m.GetCustomAttributes (true)) { + ExportAttribute export = (ca as ExportAttribute); + if (export == null) + continue; + + string name = export.Selector; + if (Skip (t, name)) + continue; + + CheckInit (t, m, name); + + bool result = bool_objc_msgSend_IntPtr (class_ptr, responds_handle, Selector.GetHandle (name)); + bool response = CheckResponse (result, t, m, ref name); + if (!response) + ReportError ("Selector not found for {0}", name); + n++; + } + } + + void CheckInit (Type t, MethodBase m, string name) + { + if (SkipInit (name, m)) + return; + + bool init = IsInitLike (name); + if (m is ConstructorInfo) { + if (!init) + ReportError ("Selector {0} used on a constructor (not a method) on {1}", name, t.FullName); + } else { + if (init) + ReportError ("Selector {0} used on a method (not a constructor) on {1}", name, t.FullName); + } + } + + bool IsInitLike (string selector) + { + if (!selector.StartsWith ("init", StringComparison.OrdinalIgnoreCase)) + return false; + return selector.Length < 5 || Char.IsUpper (selector [4]); + } + + protected virtual bool SkipInit (string selector, MethodBase m) + { + switch (selector) { + // NSAttributedString + case "initWithHTML:documentAttributes:": + case "initWithRTF:documentAttributes:": + case "initWithRTFD:documentAttributes:": + case "initWithURL:options:documentAttributes:error:": + case "initWithFileURL:options:documentAttributes:error:": + // AVAudioRecorder + case "initWithURL:settings:error:": + // NSUrlProtectionSpace + case "initWithHost:port:protocol:realm:authenticationMethod:": + case "initWithProxyHost:port:type:realm:authenticationMethod:": + // NSUserDefaults + case "initWithSuiteName:": + case "initWithUser:": + // GKScore + case "initWithCategory:": + case "initWithLeaderboardIdentifier:": + // MCSession + case "initWithPeer:securityIdentity:encryptionPreference:": + // UISegmentedControl + case "initWithItems:": + var mi = m as MethodInfo; + return mi != null && !mi.IsPublic && mi.ReturnType.Name == "IntPtr"; + default: + return false; + } + } + + protected virtual void Dispose (NSObject obj, Type type) + { + obj.Dispose (); + } + + // funny, this is how I envisioned the instance version... before hitting run :| + protected virtual bool CheckStaticResponse (bool value, Type actualType, Type declaredType, ref string name) + { + if (value) + return true; + + name = actualType.FullName + " : " + name; + return false; + } + + [Test] + public void StaticMethods () + { + Errors = 0; + int n = 0; + + IntPtr responds_handle = Selector.GetHandle ("respondsToSelector:"); + + foreach (Type t in Assembly.GetTypes ()) { + if (t.IsNested || !NSObjectType.IsAssignableFrom (t)) + continue; + + if (Skip (t) || SkipDueToAttribute (t)) + continue; + + FieldInfo fi = t.GetField ("class_ptr", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + if (fi == null) + continue; // e.g. *Delegate + IntPtr class_ptr = (IntPtr) fi.GetValue (null); + + foreach (var m in t.GetMethods (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { + if (SkipDueToAttribute (m)) + continue; + + foreach (object ca in m.GetCustomAttributes (true)) { + if (ca is ExportAttribute) { + string name = (ca as ExportAttribute).Selector; + + if (Skip (t, name)) + continue; + + bool result = bool_objc_msgSend_IntPtr (class_ptr, responds_handle, Selector.GetHandle (name)); + bool response = CheckStaticResponse (result, t, m.DeclaringType, ref name); + if (!response) + ReportError (name); + n++; + } + } + } + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} static selector validated", Errors, n); + } + } +} diff --git a/tests/introspection/ApiSignatureTest.cs b/tests/introspection/ApiSignatureTest.cs new file mode 100644 index 000000000000..2528023438d1 --- /dev/null +++ b/tests/introspection/ApiSignatureTest.cs @@ -0,0 +1,760 @@ +// +// Test the generated API selectors against typos or non-existing cases +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Reflection; +using System.Text; +using NUnit.Framework; +using System.Linq; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + + public abstract class ApiSignatureTest : ApiBaseTest { + + [DllImport ("/usr/lib/libobjc.dylib")] + // note: the returned string is not ours to free + static extern IntPtr objc_getClass (string name); + + [DllImport ("/usr/lib/libobjc.dylib")] + // note: the returned string is not ours to free + static extern IntPtr method_getTypeEncoding (IntPtr method); + + [DllImport ("/usr/lib/libobjc.dylib")] + static extern IntPtr class_getClassMethod (IntPtr klass, IntPtr selector); + + [DllImport ("/usr/lib/libobjc.dylib")] + static extern IntPtr class_getInstanceMethod (IntPtr klass, IntPtr selector); + + protected string[] Split (string encoded, out int size) + { + List elements = new List (); + int pos = 0; + string s = Next (encoded, ref pos); + int end = pos; + while (Char.IsDigit (encoded [end])) + end++; + + size = Int32.Parse (encoded.Substring (pos, end - pos)); + + if (encoded [end] != '@' || encoded [end + 1] != '0' || encoded [end + 2] != ':') { + if (!ContinueOnFailure) + Assert.Fail ("Unexpected format, missing '@0:', inside '{0}'", encoded); + return null; + } + + pos = end + 3; + + while (s != null) { + elements.Add (s); + s = Next (encoded, ref pos); + } + return elements.ToArray (); + } + + static string Next (string encoded, ref int pos) + { + // skip digits + while (pos < encoded.Length && Char.IsDigit (encoded [pos])) + pos++; + if (pos >= encoded.Length) + return null; + + StringBuilder sb = new StringBuilder (); + int acc = 0; + char c = encoded [pos]; + while (!Char.IsDigit (c) || acc > 0) { + sb.Append (c); + if (c == '{' || c == '(') + acc++; + else if (c == '}' || c == ')') + acc--; + if (++pos >= encoded.Length) + break; + c = encoded [pos]; + } + return sb.ToString (); + } + + int TypeSize (Type t) + { + return TypeSize (t, ref t); + } + + int TypeSize (Type t, ref Type real) + { + real = t; + if (!t.IsValueType) + return IntPtr.Size; // platform + if (t.IsEnum) { + foreach (var ca in t.CustomAttributes) { + if (ca.AttributeType.Name == "NativeAttribute") + return IntPtr.Size; + } + real = Enum.GetUnderlyingType (t); + } + return Marshal.SizeOf (real); + } + + protected virtual int Size (Type t, bool simd = false) + { + switch (t.Name) { + // rdar 21375616 - Breaking change with EventKit[UI] enum base type + // EventKit.EK* enums are anonymous enums in 10.10 and iOS 8, but an NSInteger in 10.11 and iOS 9. + case "EKCalendarType": + case "EKParticipantType": + case "EKParticipantRole": + case "EKParticipantStatus": + case "EKEventStatus": + case "EKSourceType": + case "EKSpan": + case "EKRecurrenceFrequency": + case "EKEventAvailability": + if (!IsOSX11OrIOS9) + return 4; + break; + case "MDLAxisAlignedBoundingBox": + return 32; // struct (Vector3, Vector3) + } + if (simd) { + switch (t.Name) { + case "Vector3i": // sizeof (vector_uint3) + case "Vector3": // sizeof (vector_float3) + return 16; + case "MDLAxisAlignedBoundingBox": + return 32; // struct (Vector3, Vector3) + } + } + int size = TypeSize (t, ref t); + return t.IsPrimitive && size < 4 ? 4 : size; + } + + protected virtual bool Skip (Type type) + { + if (type.ContainsGenericParameters) + return true; + + return false; + } + + protected virtual bool Skip (Type type, MethodBase method, string selector) + { + return SkipDueToAttribute (method); + } + + public int CurrentParameter { get; private set; } + + public MethodBase CurrentMethod { get; private set; } + + public string CurrentSelector { get; private set; } + + public Type CurrentType { get; private set; } + + const BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; + + [Test] + public void Signatures () + { + int n = 0; + Errors = 0; + + foreach (Type t in Assembly.GetTypes ()) { + + var static_type = t.IsSealed && t.IsAbstract; // e.g. [Category] + if (t.IsNested || (!static_type && !NSObjectType.IsAssignableFrom (t))) + continue; + + if (Skip (t)) + continue; + + CurrentType = t; + + FieldInfo fi = null; + if (!static_type) + fi = t.GetField ("class_ptr", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + IntPtr class_ptr = fi == null ? IntPtr.Zero : (IntPtr) fi.GetValue (null); + + foreach (MethodBase m in t.GetMethods (Flags)) + CheckMemberSignature (m, t, class_ptr, ref n); + foreach (MethodBase m in t.GetConstructors (Flags)) + CheckMemberSignature (m, t, class_ptr, ref n); + } + AssertIfErrors ("{0} errors found in {1} signatures validated", Errors, n); + } + + void CheckMemberSignature (MethodBase m, Type t, IntPtr class_ptr, ref int n) + { + var methodinfo = m as MethodInfo; + var constructorinfo = m as ConstructorInfo; + + if (methodinfo == null && constructorinfo == null) + return; + + if (m.DeclaringType != t) + return; + + CurrentMethod = m; + + foreach (object ca in m.GetCustomAttributes (true)) { + var exportAttribute = ca as ExportAttribute; + if (exportAttribute == null) + continue; + string name = exportAttribute.Selector; + + if (Skip (t, m, name)) + continue; + + CurrentSelector = name; + + // in some cases, e.g. *Delegate, we cannot use introspection but we can still do some checks + if (class_ptr == IntPtr.Zero) { + BasicChecks (m, t, ref n); + } else { + IntrospectionTest (m, methodinfo, t, class_ptr, ref n); + } + } + } + + void BasicChecks (MethodBase m, Type t, ref int n) + { + int native = 0; + int pos = CurrentSelector.IndexOf (':'); + while (pos != -1) { + native++; + pos = CurrentSelector.IndexOf (':', pos + 1); + } + var mp = m.GetParameters (); + int managed = mp.Length; + if (t.IsSealed && t.IsAbstract) { + // static types, e.g. [Category], adds a first 'This' argument for extension methods + // but we also expose static properties this way, e.g. NSUrlUtilities_NSCharacterSet + if ((managed >= 1) && (mp [0].Name == "This")) + managed--; + } + if (LogProgress) + Console.WriteLine ("{0} {1} '{2}' selector {3} : {4} == {5}", ++n, t.Name, m, CurrentSelector, native, managed); + if (native != managed) { + AddErrorLine ("Parameter count mismatch for {0} in {1}:{2} : Native {3} vs Managed {4}", + CurrentSelector, t, m.Name, native, managed); + } + } + + void IntrospectionTest (MethodBase m, MethodInfo methodinfo, Type t, IntPtr class_ptr, ref int n) + { + IntPtr sel = Selector.GetHandle (CurrentSelector); + IntPtr method; + if (methodinfo != null) + method = m.IsStatic ? class_getClassMethod (class_ptr, sel) : class_getInstanceMethod (class_ptr, sel); + else + method = class_getInstanceMethod (class_ptr, sel); + IntPtr tenc = method_getTypeEncoding (method); + string encoded = Marshal.PtrToStringAuto (tenc); + + if (LogProgress) + Console.WriteLine ("{0} {1} '{2} {3}' selector: {4} == {5}", ++n, t.Name, methodinfo != null ? methodinfo.IsStatic ? "static" : "instance" : "ctor", m, CurrentSelector, encoded); + + // NSObject has quite a bit of stuff that's not usable (except by some class that inherits from it) + if (String.IsNullOrEmpty (encoded)) + return; + + int encoded_size = -1; + string [] elements = null; + try { + elements = Split (encoded, out encoded_size); + } + catch { + } + if (elements == null) { + if (LogProgress) + Console.WriteLine ("[WARNING] Could not parse encoded signature for {0} : {1}", CurrentSelector, encoded); + return; + } + + bool result; + CurrentParameter = 0; + + if (methodinfo != null) { + // check return value + + result = Check (elements [CurrentParameter], methodinfo.ReturnType); + if (!result) + AddErrorLine ("Return Value of selector: {0} on type {1}, Type: {2}, Encoded as: {3}", CurrentSelector, t, methodinfo.ReturnType, elements [CurrentParameter]); + } + + int size = 2 * IntPtr.Size; // self + selector (@0:) + + var parameters = m.GetParameters (); + bool simd = (parameters.Length >= elements.Length); + foreach (var p in parameters) { + CurrentParameter++; + var pt = p.ParameterType; + if (CurrentParameter >= elements.Length) { + // SIMD structures are not (ios8 beta2) encoded in the signature, we ignore them + result = IgnoreSimd (CurrentSelector, t, pt); + if (!result) + AddErrorLine ("Selector: {0} on type {1}, Type: {2}, nothing encoded", CurrentSelector, t, pt); + } else { + // skip SIMD/vector parameters (as they are not encoded) + result = IgnoreSimd (CurrentSelector, t, pt); + if (result) + CurrentParameter--; + else + result = Check (elements [CurrentParameter], pt); + if (!result) + AddErrorLine ("Signature failure in {1} {0} Parameter '{4}' (#{5}) is encoded as '{3}' and bound as '{2}'", + CurrentSelector, t, pt, elements [CurrentParameter], p.Name, CurrentParameter); + } + + size += Size (pt, simd); + } + + // also ensure the encoded size match what MT (or XM) provides + // catch API errors (and should catch most 64bits issues as well) + if (size != encoded_size) + AddErrorLine ("Size {0} != {1} for {2} on {3}: {4}", encoded_size, size, CurrentSelector, t, encoded); + } + + static bool IgnoreSimd (string name, Type t, Type pt) + { + switch (pt.Name) { + case "Vector2": + case "Vector2i": + case "Vector3": + case "Vector3i": + case "Vector4": + case "Vector4i": + case "MDLAxisAlignedBoundingBox": // struct { Vector3, Vector3 } + return true; + default: + return false; + } + } + + protected virtual bool IsValidStruct (Type type, string structName) + { + switch (structName) { + // MKPolygon 'static MonoTouch.MapKit.MKPolygon _FromPoints(IntPtr, Int32)' selector: polygonWithPoints:count: == @16@0:4^{?=dd}8I12 + // NSValue 'static MonoTouch.Foundation.NSValue FromCMTime(CMTime)' selector: valueWithCMTime: == @32@0:4{?=qiIq}8 + case "?": + return type.IsValueType; // || (type.FullName == "System.IntPtr"); +#if XAMCORE_2_0 + case "CGRect": + return type.FullName == "CoreGraphics.CGRect"; + case "CGSize": + return type.FullName == "CoreGraphics.CGSize"; + case "CGPoint": + return type.FullName == "CoreGraphics.CGPoint"; +#else + case "CGRect": + return type.FullName == "System.Drawing.RectangleF"; + case "CGSize": + return type.FullName == "System.Drawing.SizeF"; + case "CGPoint": + return type.FullName == "System.Drawing.PointF"; +#endif + case "opaqueCMFormatDescription": + switch (type.Name) { + case "CMFormatDescription": + case "CMVideoFormatDescription": + case "CMAudioFormatDescription": + return true; + } + break; + case "opaqueCMSampleBuffer": + structName = "CMSampleBuffer"; + break; + case "_NSRange": + structName = "NSRange"; + break; + // textureWithContentsOfFile:options:queue:completionHandler: == v24@0:4@8@12^{dispatch_queue_s=}16@?20 + case "dispatch_queue_s": + structName = "DispatchQueue"; + break; + case "OpaqueCMClock": + structName = "CMClock"; + break; + case "OpaqueCMTimebase": + structName = "CMTimebase"; + break; + case "__CFRunLoop": + structName = "CFRunLoop"; + break; + case "_GLKVector4": + structName = "Vector4"; + break; + case "_GLKVector3": + structName = "Vector3"; + break; + case "_GLKVector2": + structName = "Vector2"; + break; + case "_GLKMatrix2": + structName = "Matrix2"; + break; + case "_GLKMatrix3": + structName = "Matrix3"; + break; + case "_GLKMatrix4": + structName = "Matrix4"; + break; + case "__CVPixelBufferPool": + structName = "CVPixelBufferPool"; + break; + case "opaqueMTAudioProcessingTap": + structName = "MTAudioProcessingTap"; + break; + case "OpaqueMIDIEndpoint": + structName = "Int32"; + break; + case "__CFDictionary": + structName = "NSDictionary"; + break; + case "__CFUUID": + // CBAttribute.UUID is defined as a CBUUID but ObjC runtime tell us it's __CFUUID + // which makes it sound like a (undocumented) toll free bridged type + structName = "CBUUID"; + break; + case "__CFString": + if (type.FullName == "System.String") + return true; + break; +#if !MONOMAC + // definition is different on OSX + case "SCNVector4": + switch (type.Name) { + case "SCNVector4": + // typedef SCNVector4 SCNQuaternion; (SceneKitTypes.h) + case "SCNQuaternion": + return true; + } + break; +#endif + case "_CGLContextObject": + structName = "CGLContext"; + break; + case "_CGLPixelFormatObject": + structName = "CGLPixelFormat"; + break; + case "OpaqueSecIdentityRef": + structName = "SecIdentity"; + break; + case "__SecTrust": + structName = "SecTrust"; + break; + case "_NSZone": + structName = "NSZone"; + break; + case "_AVBeatRange": + structName = "AVBeatRange"; + break; + case "AVAudio3DPoint": + structName = "Vector3"; + break; + case "OpaqueMusicSequence": + structName = "MusicSequence"; + break; + case "OpaqueAudioComponentInstance": + structName = "AudioUnit"; + break; + case "OpaqueAudioComponent": + structName = "AudioComponent"; + break; + case "GCQuaternion": + structName = "Quaterniond"; // OpenTK.Quaterniond + break; + case "OpaqueSecAccessControl": // El Capitan + case "__SecAccessControl": + structName = "SecAccessControl"; + break; + case "AudioChannelLayout": + // this is actually an `nint` used as a pointer (to get a unique signature for the .ctor) + // there's custom code in src/AVFoundation/AVAudioChannelLayout.cs to deal with this +#if XAMCORE_2_0 + structName = "nint"; +#else + structName = "Int32"; +#endif + break; +#if !XAMCORE_2_0 + // in compat it's a class (instead of a struct) hence this hack + case "AudioComponentDescription": + structName = "AudioComponentDescriptionNative"; + break; +#endif + } + return type.Name == structName; + } + + static Type inativeobject = typeof (INativeObject); + + protected virtual bool Check (string encodedType, Type type) + { + char c = encodedType [0]; + + if (encodedType.Length == 1) + return Check (c, type); + + switch (c) { + // GLKBaseEffect 'instance Vector4 get_LightModelAmbientColor()' selector: lightModelAmbientColor == (_GLKVector4={?=ffff}{?=ffff}{?=ffff}[4f])8@0:4 + case '(': + case '{': + string struct_name = encodedType.Substring (1, encodedType.IndexOf ('=') - 1); + return IsValidStruct (type, struct_name); + case '@': + switch (encodedType [1]) { + case '?': + return (type.Name == "NSAction") || type.BaseType.FullName == "System.MulticastDelegate"; + default: + return false; + } + case '^': + switch (encodedType [1]) { + case 'v': + // NSOpenGLContext 'instance MonoMac.OpenGL.CGLContext get_CGLContext()' selector: CGLContextObj == ^v8@0:4 + if ((CurrentType.Name == "NSOpenGLContext") && (type.Name == "CGLContext")) + return true; + // NSOpenGLPixelFormat 'instance MonoMac.OpenGL.CGLPixelFormat get_CGLPixelFormat()' selector: CGLPixelFormatObj == ^v8@0:4 + if ((CurrentType.Name == "NSOpenGLPixelFormat") && (type.Name == "CGLPixelFormat")) + return true; + if (type.Name == "ABRecord") { + if ((CurrentType.Name == "EKParticipant") || CurrentType.Name.StartsWith ("PKPayment", StringComparison.OrdinalIgnoreCase)) + return true; + } + if ((type.Name == "ABAddressBook") && (CurrentType.Name == "EKParticipant")) + return true; + return (type.FullName == "System.IntPtr"); + case 'B': + case 'd': + case 'f': + case 'I': + case 'i': + case 'c': + case 'q': + case 'Q': + case 'S': + return (type.FullName == "System.IntPtr") || Check (encodedType.Substring (1), type.GetElementType ()); + // NSInputStream 'instance Boolean GetBuffer(IntPtr ByRef, UInt32 ByRef)' selector: getBuffer:length: == c16@0:4^*8^I12 + case '*': + case '{': + // 10.7 only: NSArray 'static MonoMac.Foundation.NSArray FromObjects(IntPtr, Int32)' selector: arrayWithObjects:count: == @16@0:4^r@8I12 + case 'r': + if (type.FullName == "System.IntPtr") + return true; + return Check (encodedType.Substring (1), type.IsByRef ? type.GetElementType () : type); + case '@': + return Check ('@', type.IsByRef ? type.GetElementType () : type); + case '^': + case '?': + return (type.FullName == "System.IntPtr"); + default: + return false; + } + case 'r': + // const -> ignore + // e.g. vectorWithValues:count: == @16@0:4r^f8L12 + case 'o': + // out -> ignore + // e.g. validateValue:forKey:error: == c20@0:4N^@8@12o^@16 + case 'N': + // inout -> ignore + // e.g. validateValue:forKey:error: == c20@0:4N^@8@12o^@16 + case 'V': + // oneway -> ignore + // e.g. NSObject 'instance Void NativeRelease()' selector: release == Vv8@0:4 + return Check (encodedType.Substring (1), type); + default: + return false; + } + } + + /// + /// Check that specified encodedType match the type and caller. + /// + /// Encoded type from the ObjC signature. + /// Managed type representing the encoded type. + /// Caller's type. Useful to limit any special case. + protected virtual bool Check (char encodedType, Type type) + { + switch (encodedType) { + case '@': + return (type.IsInterface || // protocol + type.IsArray || // NSArray + (type.Name == "NSArray") || // NSArray + (type.FullName == "System.String") || // NSString + (type.FullName == "System.IntPtr") || // unbinded, e.g. internal + (type.BaseType.FullName == "System.MulticastDelegate") || // completion handler -> delegate + NSObjectType.IsAssignableFrom (type)) || // NSObject derived + inativeobject.IsAssignableFrom (type); // e.g. CGImage + case 'B': + // 64 bits only encode this + return type.FullName == "System.Boolean"; + case 'c': // char, used for C# bool + switch (type.FullName) { + case "System.Boolean": + case "System.SByte": + return true; + default: + return type.IsEnum && TypeSize (type) == 1; + } + case 'C': + switch (type.FullName) { + case "System.Byte": + // GLKBaseEffect 'instance Boolean get_ColorMaterialEnabled()' selector: colorMaterialEnabled == C8@0:4 + case "System.Boolean": + return true; + default: + return false; + } + case 'd': + switch (type.FullName) { + case "System.Double": + return true; + case "System.nfloat": + return IntPtr.Size == 8; + default: + return false; + } + case 'f': + switch (type.FullName) { + case "System.Single": + return true; + case "System.nfloat": + return IntPtr.Size == 4; + default: + return false; + } + case 'i': + switch (type.FullName) { + case "System.Int32": + return true; + case "System.nint": + return IntPtr.Size == 4; + case "EventKit.EKSourceType": + case "EventKit.EKCalendarType": + case "EventKit.EKEventAvailability": + case "EventKit.EKEventStatus": + case "EventKit.EKParticipantRole": + case "EventKit.EKParticipantStatus": + case "EventKit.EKParticipantType": + case "EventKit.EKRecurrenceFrequency": + case "EventKit.EKSpan": + case "EventKit.EKAlarmType": + // EventKit.EK* enums are anonymous enums in 10.10 and iOS 8, but an NSInteger in 10.11 and iOS 9. + if (IsOSX11OrIOS9) + goto default; + return true; + default: + return type.IsEnum && TypeSize (type) == 4; + } + case 'I': + switch (type.FullName) { + case "System.UInt32": + return true; + case "System.nint": // check + case "System.nuint": + return IntPtr.Size == 4; + default: + return type.IsEnum && TypeSize (type) == 4; + } + case 'l': + switch (type.FullName) { + case "System.Int32": + return true; + case "System.nint": + return IntPtr.Size == 4; + default: + return type.IsEnum && TypeSize (type) == 4; + } + case 'L': + switch (type.FullName) { + case "System.UInt32": + return true; + case "System.nint": // check + case "System.nuint": + return IntPtr.Size == 4; + default: + return type.IsEnum && TypeSize (type) == 4; + } + case 'q': + switch (type.FullName) { + case "System.Int64": + return true; + case "System.nint": + return IntPtr.Size == 8; + default: + return type.IsEnum && TypeSize (type) == 8; + } + case 'Q': + switch (type.FullName) { + case "System.UInt64": + return true; + case "System.nint": // check + case "System.nuint": + return IntPtr.Size == 8; + default: + return type.IsEnum && TypeSize (type) == 8; + } + case 's': + return type.FullName == "System.Int16"; + // unsigned 16 bits + case 'S': + switch (type.FullName) { + case "System.UInt16": + // NSString 'instance Char _characterAtIndex(Int32)' selector: characterAtIndex: == S12@0:4I8 + case "System.Char": + return true; + default: + return type.IsEnum && TypeSize (type) == 2; + } + case ':': + return type.Name == "Selector"; + case 'v': + return type.FullName == "System.Void"; + case '?': + return type.BaseType.FullName == "System.MulticastDelegate"; // completion handler -> delegate + case '#': + return type.FullName == "System.IntPtr" || type.Name == "Class"; + // CAMediaTimingFunction 'instance Void GetControlPointAtIndex(Int32, IntPtr)' selector: getControlPointAtIndex:values: == v16@0:4L8[2f]12 + case '[': + return type.FullName == "System.IntPtr"; + // const uint8_t * -> IntPtr + // NSCoder 'instance Void EncodeBlock(IntPtr, Int32, System.String)' selector: encodeBytes:length:forKey: == v20@0:4r*8I12@16 + case '*': + return type.FullName == "System.IntPtr"; + case '^': + return type.FullName == "System.IntPtr"; + } + return false; + } + } +} diff --git a/tests/introspection/ApiStructTest.cs b/tests/introspection/ApiStructTest.cs new file mode 100644 index 000000000000..3e29fa4a8a18 --- /dev/null +++ b/tests/introspection/ApiStructTest.cs @@ -0,0 +1,94 @@ +// +// ApiStructTest.cs: enforce structure definitions +// +// Authors: +// Aaron Bockover +// +// Copyright 2013 Xamarin, Inc. + +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using ObjCRuntime; +using Foundation; +#elif MONOMAC +using MonoMac.ObjCRuntime; +using MonoMac.Foundation; +#else +using MonoTouch.ObjCRuntime; +using MonoTouch.Foundation; +#endif + +namespace Introspection { + + [TestFixture] + public class ApiStructTest : ApiBaseTest + { + public ApiStructTest () + { + ContinueOnFailure = true; + LogProgress = true; + } + + protected virtual bool Skip (Type type) + { + return SkipDueToAttribute (type); + } + + [Test] + public void Structs () + { + int totalStructs = 0; + int totalErrors = 0; + + var structQuery = from type in Assembly.GetTypes () + where type.IsValueType && !type.IsPrimitive && !type.IsEnum && !Skip (type) + select type; + + foreach (var type in structQuery) { + totalStructs++; + if (!CheckStruct (type)) { + totalErrors++; + + if (!ContinueOnFailure) + break; + } + } + + Assert.AreEqual (0, totalErrors, + "{0} errors found in {1} structures validated", + totalErrors, totalStructs); + } + + protected virtual bool CheckStruct (Type type) + { + var success = true; + + foreach (var fi in type.GetFields ()) { + if (!CheckField (type, fi)) + success = false; + } + + return success; + } + + protected virtual bool CheckField (Type type, FieldInfo fi) + { +#if XAMCORE_2_0 + if (fi.FieldType.IsEnum && fi.FieldType.GetCustomAttribute () != null) { + if (LogProgress) + Console.Error.WriteLine ("{0} has a [Native] enum field in its definition: {1} {2}", + type.FullName, fi.FieldType, fi.Name); + return false; + } +#endif + return true; + } + } +} + diff --git a/tests/introspection/ApiTypoTest.cs b/tests/introspection/ApiTypoTest.cs new file mode 100644 index 000000000000..c39d371b4555 --- /dev/null +++ b/tests/introspection/ApiTypoTest.cs @@ -0,0 +1,476 @@ +// +// Test the generated API selectors against typos or non-existing cases +// +// Authors: +// Paola Villarreal +// +// Copyright 2015 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using NUnit.Framework; +#if XAMCORE_2_0 +using UIKit; +using Foundation; +#else +using MonoTouch.UIKit; +using MonoTouch.Foundation; +#endif + +namespace Introspection +{ + public abstract class ApiTypoTest : ApiBaseTest + { + protected ApiTypoTest () + { + ContinueOnFailure = true; + } + + public virtual bool Skip (Type baseType, string typo) { + return SkipAllowed (baseType.Name, null, typo); + } + + public virtual bool Skip (MemberInfo methodName, string typo) { + return SkipAllowed (methodName.DeclaringType.Name, methodName.Name, typo); + } + + HashSet allowed = new HashSet () { + "Aac", + "Accurracy", + "Achivements", + "Acos", + "Actionname", + "Activitiy", + "Addr", + "Adjustmentfor", + "Aifc", + "Aiff", + "Amete", + "Amr", + "Anglet", + "Arraycollation", + "Asin", + "Atan", + "Attrib", + "Attributevalue", + "Audiofile", + "Automounted", + "Autoredirect", + "Backface", + "Bary", + "Batc", + "Bim", + "Biquad", + "Bitangent", + "Blinn", + "Blit", + "Bokeh", + "Bsln", + "Bssid", + "Bzip", + "Cabac", + "Caf", // acronym: Core Audio Format + "Cancellable", + "Cavlc", + "Celp", // MPEG4ObjectID + "Characterteristic", + "Chromaticities", + "Ciff", + "Cinepak", + "Clearcoat", + "Colos", + "Commerical", + "Composable", + "Conflictserror", + "Connnect", + "Counterclock", + "Craete", + "Cubemap", + "Cmyk", // acronym: Cyan, magenta, yellow and key + "Daap", + "Dav", + "Dcip", // acronym: Digital Cinema Implementation Partners + "Deca", + "Decomposables", + "Deinterlace", + "Descendents", + "Descrete", + "Differental", + "Diffie", + "Directionfor", + "Dist", + "dlclose", + "dlerror", + "Dlfcn", + "dlopen", + "dlsym", + "Dng", + "Dns", + "Dont", + "Dop", + "Downsample", + "Downmix", // Sound terminology that means making a stereo mix from a 5.1 surround mix. + "Dpa", + "Dpad", // Directional pad (D-pad) + "Droste", + "Dtls", + "dy", + "Ebu", + "Ecc", + "Eof", // acronym End-Of-File + "Emagic", + "Emaili", + "Eppc", + "Exhange", + "Exp", + "Flipside", + "Formati", + "Fov", + "Framebuffer", + "Framesetter", + "Freq", + "Ftps", + "Func", + "Gadu", + "Geocoder", + "Gpp", + "Hdmi", + "Hdr", + "Hevc", // CMVideoCodecType / High Efficiency Video Coding + "Hfp", + "Hipass", + "Hls", + "Hrtf", // acronym used in AUSpatializationAlgorithm + "Hvxc", // MPEG4ObjectID + "Icq", + "Identd", + "Imagefor", + "Imap", + "Imaps", + "Img", + "Inser", + "Interac", + "Interframe", + "Interitem", + "Intermenstrual", + "Intoi", + "Ios", + "Ipp", + "Iptc", + "Ircs", + "Itu", + "Jfif", + "Json", + "Keyerror", + "Keyi", + "Keyspace", + "ks", + "Langauges", + "Ldaps", + "Lerp", + "Linecap", + "Lingustic", + "Lod", + "Lopass", + "Lowlevel", + "Matchingcoalesce", + "Metacharacters", + "Minification", + "Mobike", // acronym + "Morpher", + "Mtu", // acronym + "Mtc", // acronym + "Mul", + "Mult", + "Multipeer", + "Muxed", + "nfloat", + "nint", + "Nntps", + "Ntlm", + "Ntsc", + "nuint", + "Numbernumber", + "Nyquist", + "Objectfor", + "Occlussion", + "Ocurrences", + "Oid", + "Oneup", // TVElementKeyOneupTemplate + "Orthographyrange", + "ove", + "Paeth", // PNG filter + "Pausable", + "Pcl", + "Pcm", + "Pdu", + "Persistance", + "Pesented", + "Pfs", // acronym + "Pkcs", + "Placemark", + "Playthrough", + "Pointillize", + "Polyline", + "Popularimeter", + "Prerolls", + "Preseti", + "Propogate", + "Psec", + "Pvrtc", // MTLBlitOption - PowerVR Texture Compression + "Quaterniond", + "Qura", + "Reacquirer", + "Reinvitation", + "Reinvite", + "Replayable", + "Requestwith", + "Rgb", + "Rgba", + "Roi", + "Romm", // acronym: Reference Output Medium Metric + "Rpa", + "Rpn", // acronym + "Rssi", + "Rtsp", + "Scn", + "Sdk", + "Sdtv", // acronym: Standard Definition Tele Vision + "Seekable", + "Shadable", + "Sharegroup", + "Siemen", + "Sinh", + "Sint", // as in "Signed Integer" + "Slerp", + "Slomo", + "Smpte", + "Snapshotter", + "Snorm", + "Sobel", + "Spacei", + "Sqrt", + "Srgb", + "Ssid", + "Standarize", + "Stateful", + "Stateright", + "Subbeat", + "Subcardioid", + "Subentities", + "Subheadline", + "Submesh", + "Submeshes", + "Subpixel", + "Subsec", + "Superentity", + "Sym", + "Synchronizable", + "Tanh", + "Texcoord", + "Texel", + "th", + "Threadgroup", + "Threadgroups", + "Thumbstick", + "Timelapse", + "Timelapses", + "Tls", + "Tlv", + "Toi", + "Truncantion", + "Tweening", + "tx", + "ty", + "Udi", + "Udp", + "Unconfigured", + "Undecodable", + "Underrun", + "Unorm", + "Unprepare", + "Unproject", + "Uterance", + "Utf", + "Uti", + "Varispeed", + "Vergence", + "Vnode", + "Vpn", + "Whitespaces", + "Writeability", + "Xpc", + "xy", + "Xyz", + "yuvs", + "yx", + "yy", + "Yyy", +#if !XAMCORE_2_0 + // classic only mistakes - that should not change anymore + "Timetime", + "Rectfrom", + "Distancefrom", + "Calendarc", + "Negotiat", + "Trus", + "Placemarks", + "Chage", + "Elipse", + "intptr", + "rbool", + "rint", + "rfloat", + "rdouble", + "rintptr", + "cgsize", + "cgpoint", + "cgrect", + "nsrange", + "stret", + "monotouch", + "xamarin", + "Dimiss", + "Owneroptions", + "Delegat", + "Nibfor", + "Delegatequeue", + "Sispatch", +#endif + }; + + // ease maintenance of the list + HashSet used = new HashSet (); + + bool SkipAllowed (string typeName, string methodName, string typo) + { + if (allowed.Contains (typo)) { + used.Add (typo); + return true; + } + return false; + } + + bool IsObsolete (MemberInfo mi) + { + if (mi == null) + return false; + if (mi.GetCustomAttributes (true).Any ()) + return true; + return IsObsolete (mi.DeclaringType); + } + + [Test] + public void TypoTest () + { + var types = Assembly.GetTypes (); + int totalErrors = 0; + foreach (Type t in types) { + if (t.IsPublic && !IsObsolete (t)) { + string txt = NameCleaner (t.Name); + var typo = GetTypo (txt); + if (typo.Length > 0 ) { + if (!Skip (t, typo)) { + ReportError ("Typo in TYPE: {0} - {1} ", t.Name, typo); + totalErrors++; + } + } + + var fields = t.GetFields (); + foreach (FieldInfo f in fields) { + if (!f.IsPublic && !f.IsFamily && !IsObsolete (f)) + continue; + + txt = NameCleaner (f.Name); + typo = GetTypo (txt); + if (typo.Length > 0) { + if (!Skip (f, typo)) { + ReportError ("Typo in FIELD name: {0} - {1}, Type: {2}", f.Name, typo, t.Name); + totalErrors++; + } + } + } + + var methods = t.GetMethods (); + foreach (MethodInfo m in methods) { + if (!m.IsPublic && !m.IsFamily && !IsObsolete (m)) + continue; + + txt = NameCleaner (m.Name); + typo = GetTypo (txt); + if (typo.Length > 0) { + if (!Skip (m, typo)) { + ReportError ("Typo in METHOD name: {0} - {1}, Type: {2}", m.Name, typo, t.Name); + totalErrors++; + } + } +#if false + var parameters = m.GetParameters (); + foreach (ParameterInfo p in parameters) { + txt = NameCleaner (p.Name); + typo = GetTypo (txt); + if (typo.Length > 0) { + ReportError ("Typo in PARAMETER Name: {0} - {1}, Method: {2}, Type: {3}", p.Name, typo, m.Name, t.Name); + totalErrors++; + } + } +#endif + } + } + } +#if false + // ease removal of unrequired values (but needs to be checked for every profile) + var unused = allowed.Except (used); + foreach (var typo in unused) + Console.WriteLine ("Unused entry \"{0}\"", typo); +#endif + Assert.IsTrue ((totalErrors == 0), "We have {0} typos!", totalErrors); + } + + public abstract string GetTypo (string txt); + + static StringBuilder clean = new StringBuilder (); + + static string NameCleaner (string name) + { + clean.Clear (); + foreach (char c in name) { + if (Char.IsUpper (c)) { + clean.Append (' ').Append (c); + continue; + } + if (Char.IsDigit (c)) { + clean.Append (' '); + continue; + } + switch (c) { + case '<': + case '>': + case '_': + clean.Append (' '); + break; + default: + clean.Append (c); + break; + } + } + return clean.ToString (); + } + } +} \ No newline at end of file diff --git a/tests/introspection/ApiWeakPropertyTest.cs b/tests/introspection/ApiWeakPropertyTest.cs new file mode 100644 index 000000000000..932a98ddf7d1 --- /dev/null +++ b/tests/introspection/ApiWeakPropertyTest.cs @@ -0,0 +1,110 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Reflection; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + [Preserve (AllMembers = true)] + public abstract class ApiWeakPropertyTest : ApiBaseTest { + + /// + /// Override if you want to skip testing the specified type. + /// + /// Type to be tested + protected virtual bool Skip (Type type) + { + switch (type.Name) { + case "LinkWithAttribute": // LinkWithAttribute.WeakFrameworks + return true; + } + return false; + } + + /// + /// Override if you want to skip testing the specified property. + /// + /// Property candidate. + protected virtual bool Skip (PropertyInfo property) + { + return false; + } + + [Test] + public void WeakPropertiesHaveArgumentSemantic () + { + var failed_properties = new List (); + + Errors = 0; + int c = 0, n = 0; + foreach (Type t in Assembly.GetTypes ()) { + if (Skip (t) || SkipDueToAttribute (t)) + continue; + + if (LogProgress) + Console.WriteLine ("{0}. {1}", c++, t.FullName); + + foreach (var p in t.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { + // looking for properties with setters only + if (!p.CanWrite) + continue; + + if (SkipDueToAttribute (p)) + continue; + + if (Skip (p)) + continue; + + string name = p.Name; + if (!name.StartsWith ("Weak")) + continue; + + string error; + if (CheckArgumentSemantic (p.GetMethod, out error)) { + ReportError (error); + failed_properties.Add (p.ToString ()); + } + if (CheckArgumentSemantic (p.SetMethod, out error)) { + ReportError (error); + failed_properties.Add (p.ToString ()); + } + n++; + } + } + Assert.AreEqual (0, Errors, "{0} errors found in {1} fields validated: {2}", Errors, n, string.Join (", ", failed_properties)); + } + + bool CheckArgumentSemantic (MethodInfo meth, out string error) + { + error = null; + var export = meth.GetCustomAttribute (); + if (export == null) { + error = String.Format ("{0}.{1} has no [Export]", meth.DeclaringType.FullName, meth.Name); + return true; + } + + switch (export.ArgumentSemantic) { + case ArgumentSemantic.Assign: // Also case ArgumentSemantic.UnsafeUnretained: + case ArgumentSemantic.Copy: + case ArgumentSemantic.Retain: // case ArgumentSemantic.Strong: + case ArgumentSemantic.Weak: + return false; + default: + error = String.Format ("{0}.{1} has incorrect ArgumentSemantics: {2}", meth.DeclaringType.FullName, meth.Name, export.ArgumentSemantic); + return true; + } + } + } +} \ No newline at end of file diff --git a/tests/introspection/CoreSelectorTest.cs b/tests/introspection/CoreSelectorTest.cs new file mode 100644 index 000000000000..40f471020d1f --- /dev/null +++ b/tests/introspection/CoreSelectorTest.cs @@ -0,0 +1,130 @@ +// +// Test the generated API selectors against typos or non-existing cases +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013 Xamarin Inc. All rights reserved. +// + +using System; +using System.Reflection; +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#elif MONOMAC +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif + +namespace Introspection { + + public abstract class CoreSelectorTest : ApiSelectorTest { + + protected override bool CheckResponse (bool value, Type actualType, MethodBase method, ref string name) + { + if (value) + return true; + + var declaredType = method.DeclaringType; + + switch (name) { + // optional stuff defined in NSObject (but not implemented by every subclasses) + case "encodeWithCoder:": + case "objectDidEndEditing:": + case "commitEditing": + case "commitEditingWithDelegate:didCommitSelector:contextInfo:": + if (declaredType.Name == "NSObject") + return true; + break; + // internal stuff that must be used + case "_setCFClientFlags:callback:context:": + case "_scheduleInCFRunLoop:forMode:": + case "_unscheduleFromCFRunLoop:forMode:": + // init* works (see monotouchtest.app) but does not respond when queried + case "initWithFileAtPath:": + case "initWithData:": + case "initWithURL:": + if (declaredType.Name == "NSInputStream") + return true; + break; + // init* works (see monotouchtest.app) but does not respond when queried + case "initToMemory": + case "initToFileAtPath:append:": + if (declaredType.Name == "NSOutputStream") + return true; + break; + // init* works (see monotouchtest.app) but does not respond when queried + case "initWithFileDescriptor:": + case "initWithFileDescriptor:closeOnDealloc:": + if (declaredType.Name == "NSFileHandle") + return true; + break; + case "initWithString:": + case "initWithString:attributes:": + case "initWithAttributedString:": + if (declaredType.Name == "NSAttributedString" || declaredType.Name == "NSMutableAttributedString") + return true; + break; + } + return base.CheckResponse (value, actualType, method, ref name); + } + + protected override bool Skip (Type type) + { + switch (type.Name) { + case "MTLRenderPassAttachmentDescriptor": + // This is an abstract(-ish...) type, iOS allows creating an instance of it, but the instance doesn't respond to most of the selector in the headers. + return true; + } + + return base.Skip (type); + } + + protected override IntPtr GetClassForType (Type type) + { + switch (type.Namespace) { + case "MonoTouch.Metal": + case "MonoMac.Metal": + case "Metal": + switch (type.Name) { + case "MTLArgument": + case "MTLArrayType": + case "MTLCompileOptions": + case "MTLComputePipelineDescriptor": + case "MTLComputePipelineReflection": + case "MTLDepthStencilDescriptor": + case "MTLRenderPassAttachmentDescriptor": + case "MTLRenderPassColorAttachmentDescriptor": + case "MTLRenderPassDepthAttachmentDescriptor": + case "MTLRenderPassDescriptor": + case "MTLRenderPassStencilAttachmentDescriptor": + case "MTLRenderPipelineColorAttachmentDescriptor": + case "MTLRenderPipelineDescriptor": + case "MTLRenderPipelineReflection": + case "MTLSamplerDescriptor": + case "MTLStencilDescriptor": + case "MTLStructMember": + case "MTLStructType": + case "MTLTextureDescriptor": + case "MTLVertexAttribute": + case "MTLVertexAttributeDescriptor": + case "MTLVertexBufferLayoutDescriptor": + case "MTLVertexDescriptor": + var ctor = type.GetConstructor (Type.EmptyTypes); + using (var obj = ctor.Invoke (null) as NSObject) { + return IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle ("class")); + } + } + break; + } + + return base.GetClassForType (type); + } + } +} diff --git a/tests/introspection/EnvironmentVariable.cs b/tests/introspection/EnvironmentVariable.cs new file mode 100644 index 000000000000..52214ccb38bd --- /dev/null +++ b/tests/introspection/EnvironmentVariable.cs @@ -0,0 +1,19 @@ +using System; + +namespace Xamarin.Utils { + // Boolean variable that defaults to false, unless a environmental variable is set. Setting value explictly overrides all other values. + class LatchedEnvironmentVariable { + bool envVariable; + bool? setValue; + + internal LatchedEnvironmentVariable (string variableName) + { + envVariable = !String.IsNullOrEmpty (Environment.GetEnvironmentVariable (variableName)); + } + + internal bool Value { + set { setValue = value; } + get { return setValue.HasValue ? setValue.Value : envVariable; } + } + } +} diff --git a/tests/introspection/Mac/Info.plist b/tests/introspection/Mac/Info.plist new file mode 100644 index 000000000000..af788969bc64 --- /dev/null +++ b/tests/introspection/Mac/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDisplayName + apitest + CFBundleIdentifier + com.xamarin.introspection + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.7 + NSPrincipalClass + NSApplication + LSApplicationCategoryType + public.app-category.developer-tools + CFBundleName + introspection + + diff --git a/tests/introspection/Mac/Mac.cs b/tests/introspection/Mac/Mac.cs new file mode 100644 index 000000000000..170543089c2d --- /dev/null +++ b/tests/introspection/Mac/Mac.cs @@ -0,0 +1,31 @@ +// +// Mac-specific Helpers +// +// Authors: +// Sebastien Pouliot +// Aaron Bockover +// +// Copyright 2012-2016 Xamarin Inc. All rights reserved. +// + +using System; + +namespace Introspection { + + public static class Mac { + public static readonly Version Version_10_7 = new Version (10, 7); + public static readonly Version Version_10_8 = new Version (10, 8); + public static readonly Version Version_10_9 = new Version (10, 9); + public static readonly Version Version_10_10 = new Version (10, 10); + public static readonly Version Version_10_11 = new Version (10, 11); + + static PlatformInfo host => PlatformInfo.Host; + + public static bool CheckSystemVersion (int major, int minor) => host.Version >= new Version (major, minor); + public static bool Is32BitMavericks => host.IsArch32 && IsAtLeast (Version_10_9); + public static bool IsYosemiteOrHigher => IsAtLeast (Version_10_10); + public static bool IsElCapitanOrHigher => IsAtLeast (Version_10_11); + public static bool IsAtLeast (int major, int minor) => IsAtLeast (new Version (major, minor)); + public static bool IsAtLeast (Version version) => host.IsMac && host.Version >= version; + } +} diff --git a/tests/introspection/Mac/MacApiCtorInitTest.cs b/tests/introspection/Mac/MacApiCtorInitTest.cs new file mode 100644 index 000000000000..0defbe53952a --- /dev/null +++ b/tests/introspection/Mac/MacApiCtorInitTest.cs @@ -0,0 +1,243 @@ +// +// Mac-specific `init*` selectors validations +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013,2015 Xamarin Inc. All rights reserved. +// + +using System; +using System.Collections.Generic; + +#if XAMCORE_2_0 +using Foundation; +#else +using MonoMac.Foundation; +#endif + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + public class MacApiCtorInitTest : ApiCtorInitTest { + + public MacApiCtorInitTest () + { + //LogProgress = true; + ContinueOnFailure = true; + } + + protected override bool Skip (Attribute attr) + { + return base.Skip (attr); + } + + protected override bool Skip (Type type) + { + switch (type.FullName) { + // These should be DisableDefaultCtor but can't due to backward compat + case "MonoMac.EventKit.EKParticipant": + case "EventKit.EKParticipant": + case "XamCore.CoreImage.CISampler": + case "CoreImage.CISampler": + return true; + // OSX 10.8+ + case "MonoMac.AppKit.NSSharingService": + case "AppKit.NSSharingService": + case "MonoMac.AppKit.NSSharingServicePicker": + case "AppKit.NSSharingServicePicker": + case "MonoMac.Foundation.NSUserNotification": + case "Foundation.NSUserNotification": + case "MonoMac.Foundation.NSUserNotificationCenter": + case "Foundation.NSUserNotificationCenter": + case "MonoMac.AVFoundation.AVPlayerItemVideoOutput": + case "AVFoundation.AVPlayerItemVideoOutput": + case "MonoMac.Foundation.NSUuid": + case "Foundation.NSUuid": + if (!Mac.CheckSystemVersion (10, 8)) + return true; + break; + // Native exception coming from [NSWindow init] which calls + // [NSWindow initWithContentRect:styleMask:backing:defer] + case "MonoMac.AppKit.NSWindow": + case "AppKit.NSWindow": + return true; +#if !XAMCORE_2_0 + case "MonoMac.AppKit.NSToolbar": // mono[10518:626783] *** -[__NSDictionaryM removeObjectForKey:]: key cannot be nil + case "MonoMac.SceneKit.SCNRenderer": // -[SCNRenderer init]: unrecognized selector sent to instance 0x7c6446c0 + case "MonoMac.SceneKit.SCNLookAtConstraint": + return true; +#endif + case "MonoMac.Foundation.NSUrlSession": + case "Foundation.NSUrlSession": + case "MonoMac.Foundation.NSUrlSessionTask": + case "Foundation.NSUrlSessionTask": + case "MonoMac.Foundation.NSUrlSessionDataTask": + case "Foundation.NSUrlSessionDataTask": + case "MonoMac.Foundation.NSUrlSessionUploadTask": + case "Foundation.NSUrlSessionUploadTask": + case "MonoMac.Foundation.NSUrlSessionDownloadTask": + case "Foundation.NSUrlSessionDownloadTask": + case "MonoMac.Foundation.NSUrlSessionConfiguration": + case "Foundation.NSUrlSessionConfiguration": + // These types were introduced as 64-bit only in Mavericks, and 32+64bits in Yosemite. We can't + // express that with our AvailabilityAttribute, we set it as available (for all architectures, since + // we can't distinguish them) starting with Mavericks. + if (Mac.Is32BitMavericks) + return true; + break; + + case "GLKit.GLKSkyboxEffect": + // Crashes inside libGL.dylib, most likely because something hasn't been initialized yet, because + // I can reproduce in an Xcode project if I put [[GLKSkyboxEffect alloc] init]; in main, but it doesn't + // crash in applicationDidFinishLaunching. + // + // frame #0: 0x00007fff8d570db1 libGL.dylib`glGetError + 13 + // frame #1: 0x0000000100025542 GLKit`-[GLKEffect initWithPropertyArray:] + 1142 + // frame #2: 0x0000000100022c2d GLKit`-[GLKSkyboxEffect init] + 493 + // + if (IntPtr.Size == 8) + return true; + break; + +#if !XAMCORE_3_0 + case "SpriteKit.SKView": + // Causes a crash later. Filed as radar://18440271. + // Apple said they won't fix this ('init' isn't a designated initializer) + if (IntPtr.Size == 8) + return true; + break; +#endif + + case "MonoMac.AppKit.NSSpeechRecognizer": + case "AppKit.NSSpeechRecognizer": + // Makes OSX put up "a download is required for speech recognition" dialog. + return true; + + case "MonoMac.Foundation.NSUserActivity": + case "Foundation.NSUserActivity": + // Crashes by default: + // Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Caller did not provide an activityType, and this process does not have a NSUserActivityTypes in its Info.plist. + // but since it looks like the constructor is usable with the proper Info.plist, we can't remove it. + return true; + } + + switch (type.Namespace) { + // OSX 10.8+ + case "MonoMac.Accounts": + case "Accounts": + case "MonoMac.GameKit": + case "GameKit": + case "MonoMac.Social": + case "Social": + case "MonoMac.StoreKit": + case "StoreKit": + if (!Mac.CheckSystemVersion (10, 8)) + return true; + break; + case "SceneKit": + case "MonoMac.SceneKit": + if (!Mac.CheckSystemVersion (10, 8) || IntPtr.Size != 8) + return true; + break; + } + + return base.Skip (type); + } + + protected override void CheckNSObjectProtocol (NSObject obj) + { + switch (obj.GetType ().Name) { + case "NSString": + // according to bots `isKindOf (null)` returns true before Yosemite + break; + case "SBObject": + // *** NSForwarding: warning: object 0x77a49a0 of class '__NSMessageBuilder' does not implement doesNotRecognizeSelector: -- abort + break; + default: + base.CheckNSObjectProtocol (obj); + break; + } + } + + protected override void CheckToString (NSObject obj) + { + switch (obj.GetType ().FullName) { + // native crash calling MonoMac.Foundation.NSObject.get_Description () + case "WebKit.WKNavigationAction": + case "WebKit.WKFrameInfo": // EXC_BAD_ACCESS (code=1, address=0x0) + case "MonoMac.Foundation.NSUrlConnection": + case "Foundation.NSUrlConnection": + case "MonoMac.AppKit.NSLayoutConstraint": // Unable to create description in descriptionForLayoutAttribute_layoutItem_coefficient. Something is nil + case "AppKit.NSLayoutConstraint": + case "MonoMac.AVFoundation.AVPlayerItemTrack": + case "AVFoundation.AVPlayerItemTrack": + // 10.8 + case "MonoMac.AVFoundation.AVComposition": + case "AVFoundation.AVComposition": + case "MonoMac.GameKit.GKPlayer": // Crashing on 10.8.3 from the Apple beta channel for abock (on 2013-01-30) + case "GameKit.GKPlayer": + case "MonoMac.AVFoundation.AVAssetResourceLoadingRequest": // Crashing on 10.9.1 for abock (2014-01-13) + case "AVFoundation.AVAssetResourceLoadingRequest": + case "MonoMac.AVFoundation.AVAssetResourceLoadingDataRequest": // Crashes on 10.9.3 for chamons (constructor found in AVCompat) + case "AVFoundation.AVAssetResourceLoadingDataRequest": + case "MonoMac.AVFoundation.AVCaptureDeviceInputSource": // Crashes on 10.9.5 + case "AVFoundation.AVCaptureDeviceInputSource": + break; + default: + base.CheckToString (obj); + break; + } + } + + static List do_not_dispose = new List (); + + protected override void Dispose (NSObject obj, Type type) + { + switch (type.FullName) { + // FIXME: those crash the application when Dispose is called + case "MonoMac.JavaScriptCore.JSManagedValue": + case "JavaScriptCore.JSManagedValue": + // JSManagedValue crashes in Yosemite (b7), but not Mavericks. + if (!Mac.CheckSystemVersion (10, 10)) + goto default; + goto case "MonoMac.ImageKit.IKScannerDeviceView"; // fallthrough + case "MonoMac.ImageKit.IKScannerDeviceView": // 19835 + case "ImageKit.IKScannerDeviceView": + case "MonoMac.AppKit.NSFontPanel": // *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x11491cc00 of class NSButton was deallocated while key value observers were still registered with it. + case "AppKit.NSFontPanel": + case "MonoMac.AVFoundation.AVAudioRecorder": // same on iOS + case "AVFoundation.AVAudioRecorder": + case "MonoMac.Foundation.NSUrlConnection": + case "Foundation.NSUrlConnection": + // 10.8: + case "MonoMac.Accounts.ACAccount": // maybe the default .ctor is not allowed ? + case "Accounts.ACAccount": + case "MonoMac.Accounts.ACAccountCredential": + case "Accounts.ACAccountCredential": + case "MonoMac.Accounts.ACAccountStore": + case "Accounts.ACAccountStore": + case "MonoMac.Accounts.ACAccountType": + case "Accounts.ACAccountType": + case "MonoMac.CoreData.NSPersistentStoreCoordinator": + case "CoreData.NSPersistentStoreCoordinator": + do_not_dispose.Add (obj); + break; + // 10.11 + case "MonoMac.CoreImage.CIImageAccumulator": + case "CoreImage.CIImageAccumulator": + case "WebKit.WKNavigation": + // crashes on El Capitan (b2) but not before + if (!Mac.CheckSystemVersion (10, 11)) + goto default; + do_not_dispose.Add (obj); + break; + default: + base.Dispose (obj, type); + break; + } + } + } +} diff --git a/tests/introspection/Mac/MacApiFieldTest.cs b/tests/introspection/Mac/MacApiFieldTest.cs new file mode 100644 index 000000000000..0af31f50c047 --- /dev/null +++ b/tests/introspection/Mac/MacApiFieldTest.cs @@ -0,0 +1,220 @@ +// +// Mac specific fields validator +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012 Xamarin Inc. All rights reserved. +// + +using System; +using System.Linq; +using System.Reflection; + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + public class MacApiFieldTest : ApiFieldTest { + + public MacApiFieldTest () + { + ContinueOnFailure = true; + } + + static bool IsUnified { + get { + return AppDomain.CurrentDomain.GetAssemblies ().Any (x => x.FullName.Contains ("Xamarin.Mac")); + } + } + + protected override bool Skip (Type type) + { + switch (type.FullName) { + // OS X 10.8 + + case "MonoMac.AppKit.NSSharingService": + case "AppKit.NSSharingService": + case "MonoMac.Foundation.NSUserNotification": + case "Foundation.NSUserNotification": + return !Mac.CheckSystemVersion (10, 8); + } + + switch (type.Namespace) { + // OSX 10.8+ + case "MonoMac.Accounts": + case "Accounts": + case "MonoMac.GameKit": + case "GameKit": + case "MonoMac.Social": + case "Social": + return !Mac.CheckSystemVersion (10, 8); + case "SceneKit": + case "MonoMac.SceneKit": + return !Mac.CheckSystemVersion (10, 8) || IntPtr.Size != 8; + default: + return false; + } + } + + protected override bool Skip (PropertyInfo p) + { + switch (p.DeclaringType.Name) { + case "NSUrlSessionDownloadDelegate": + switch (p.Name) { + case "TaskResumeDataKey": + // This field was introduced as 64-bit only in Mavericks, and 32+64bits in Yosemite. We can't + // express that with our AvailabilityAttribute, we set it as available (for all architectures, since + // we can't distinguish them) starting with Mavericks. + if (Mac.Is32BitMavericks) + return true; + break; + } + break; + } + + switch (p.Name) { + // NSTableView + case "RowViewKey": + return true; + // NSBitmapImageRep + case "CompressionMethod": + case "CompressionFactor": + case "DitherTransparency": + return true; + // CIImage 10.8+ + case "AutoAdjustFeaturesKey": // kCIImageAutoAdjustFeatures - documented in 10.8 + case "AutoAdjustRedEyeKey": + case "AutoAdjustEnhanceKey": + case "CIImagePropertiesKey": + return true; + // CIImage + case "CIImageColorSpaceKey": + return true; // returns null but documented prior to 10.8 + // CLLocation 10.8+ + case "ErrorUserInfoAlternateRegionKey": // kCLErrorUserInfoAlternateRegionKey also returns null on iOS + return true; + // NSUrl 10.8+ + case "PathKey": + return !Mac.CheckSystemVersion (10, 8); + // AVMediaCharacteristic 10.8+ + case "IsMainProgramContent": + case "IsAuxiliaryContent": + case "ContainsOnlyForcedSubtitles": + case "TranscribesSpokenDialogForAccessibility": + case "DescribesMusicAndSoundForAccessibility": + case "DescribesVideoForAccessibility": + return !Mac.CheckSystemVersion (10, 8); + // AVVideo 10.8+ + case "ProfileLevelH264Main32": + return !Mac.CheckSystemVersion (10, 8); + // AVMetadata 10.8+ + case "QuickTimeUserDataKeyTaggedCharacteristic": + return !Mac.CheckSystemVersion (10, 8); + // CIDetector + case "TypeFace": // CIDetectorTypeFace - documented as available in 10.7 + case "Accuracy": // CIDetectorAccuracy 10.7 + case "AccuracyLow": // CIDetectorAccuracyLow 10.7 + case "AccuracyHigh": // CIDetectorAccuracyHigh 10.7 + return true; + // CIDetector + case "ImageOrientation": // documented in 10.8 + case "Tracking": + case "MinFeatureSize": + return true; + // CGImageProperties - all new (10.7) values are missing (from pre-6 iOS too iirc) + case "ExifCameraOwnerName": // kCGImagePropertyExifCameraOwnerName + case "ExifBodySerialNumber": // kCGImagePropertyExifBodySerialNumber + case "ExifLensSpecification": // kCGImagePropertyExifLensSpecification + case "ExifLensMake": // kCGImagePropertyExifLensMake + case "ExifLensModel": // kCGImagePropertyExifLensModel + case "ExifLensSerialNumber": // kCGImagePropertyExifLensSerialNumber + return true; + // ACErrorDomain is _listed_ in the 10.8 Accounts Changes but like iOS it's not documented anywhere else (and does not seems to exists) + case "ErrorDomain": + // ACAccountStoreDidChangeNotification - documented in 10.8 + case "ChangeNotification": + // ACAccountType - documented in 10.8 + case "Twitter": // ACAccountTypeIdentifierTwitter + case "SinaWeibo": + case "Facebook": + case "AppId": // ACFacebookAppIdKey + case "Permissions": // ACFacebookPermissionsKey + case "Audience": // *** NOT documented in 10.8 - but part of our API enhancement + case "Everyone": // ^ MonoMac.Accounts.ACFacebookAudienceValue.Everyone + case "Friends": // ^ MonoMac.Accounts.ACFacebookAudienceValue.Friends + case "OnlyMe": // ^ MonoMac.Accounts.ACFacebookAudienceValue.OnlyMe + return true; + // MonoMac.CoreServices.CFHTTPMessage - document in 10.9 but returns null + case "_AuthenticationSchemeOAuth1": + return true; + default: + return base.Skip (p); + } + } + + protected override bool Skip (string constantName) + { + switch (constantName) { + // Only there for API compat + case "kSecUseNoAuthenticationUI": + case "kSecUseOperationPrompt": + return !IsUnified; + // MonoMac.CoreServices.CFHTTPMessage - document in 10.9 but returns null + case "kCFHTTPAuthenticationSchemeOAuth1": + return true; + // kCLErrorUserInfoAlternateRegionKey also returns null on iOS + case "kCLErrorUserInfoAlternateRegionKey": + return true; + case "NSURLSessionTransferSizeUnknown": + case "NSURLSessionDownloadTaskResumeData": + if (Mac.Is32BitMavericks) + return true; + goto default; + default: + return base.Skip (constantName); + } + } + + protected override string FindLibrary (string libraryName, bool requiresFullPath = false) + { + switch (libraryName) { + case "CFNetwork": + if (Mac.IsAtLeast (10,8)) + break; + return "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/CFNetwork"; + case "CoreText": + case "CoreGraphics": + if (Mac.IsAtLeast (10,8)) + break; + return string.Format ("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/{0}.framework/{0}", libraryName); + case "ImageIO": + if (Mac.IsAtLeast (10,9)) + break; + return "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ImageIO.framework/ImageIO"; + case "CoreImage": + // generated code uses QuartzCore correctly - even if the [Field] property is wrong + libraryName = "QuartzCore"; + break; + case "QuartzComposer": + case "PdfKit": + case "ImageKit": + // generated code uses Quartz correctly - even if the [Field] property is wrong + libraryName = "Quartz"; + break; + case "CoreBluetooth": + if (Mac.IsYosemiteOrHigher) { + // CoreBluetooth is in /System/Library/Frameworks/CoreBluetooth.framework starting with Yosemite. + break; + } + + // CoreBluetooth is inside IOBluetooth.framework in earlier OSXs + return "/System/Library/Frameworks/IOBluetooth.framework/Versions/A/Frameworks/CoreBluetooth.framework/CoreBluetooth"; + case "SearchKit": + return "/System/Library/Frameworks/CoreServices.framework/Frameworks/SearchKit.framework/SearchKit"; + } + + return base.FindLibrary (libraryName, requiresFullPath); + } + } +} diff --git a/tests/introspection/Mac/MacApiPInvokeTest.cs b/tests/introspection/Mac/MacApiPInvokeTest.cs new file mode 100644 index 000000000000..e74f5fdac107 --- /dev/null +++ b/tests/introspection/Mac/MacApiPInvokeTest.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using System.Reflection; + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + public class MacApiPInvokeTest : ApiPInvokeTest { + protected override bool SkipLibrary (string libraryName) + { + switch (libraryName){ + case "/System/Library/Frameworks/OpenGL.framework/OpenGL": + return true; + } + return base.SkipLibrary (libraryName); + } + + static bool IsUnified { + get + { + return AppDomain.CurrentDomain.GetAssemblies().Any(x => x.FullName.Contains("Xamarin.Mac")); + } + } + + protected override bool Skip (Type type) + { + string typeName = type.ToString (); + bool is32Bit = IntPtr.Size == 4; + if (is32Bit && typeName.StartsWith ("MapKit", StringComparison.Ordinal)) // MapKit is 64-bit only + return true; + + switch (type.Namespace) { + case "SceneKit": + case "MonoMac.SceneKit": + if (is32Bit) + return true; + break; + } + + switch (typeName) { + case "MonoMac.GameController.GCExtendedGamepadSnapshot": // These next 4 are in the compat API, even if they don't work. + case "MonoMac.GameController.GCGamepadSnapshot": + case "MonoMac.GameController.GCExtendedGamepadSnapShotDataV100": + case "MonoMac.GameController.GCGamepadSnapShotDataV100": + return !IsUnified; + case "GameController.GCGamepadSnapShotDataV100": // These are 64-bit only + case "GameController.GCExtendedGamepadSnapShotDataV100": + return is32Bit; + case "MonoMac.AudioToolbox.AudioSession": // These are iOS APIs that were mistakenly pulled into OSX. Removed in unified but not classic + case "MonoMac.AudioUnit.AudioUnitUtils": + return !IsUnified; // If these are in unified, don't skip, we want to scream + } + + return base.Skip(type); + } + + protected override bool Skip (string symbolName) + { + switch (symbolName) { + case "SKTerminateForInvalidReceipt": // Only there for API compat + return !IsUnified; + } + return false; + } + + protected override bool SkipAssembly (Assembly a) + { + // too many things are missing from XM 32bits bindings + // and the BCL is identical for 64 bits (no need to test it 3 times) +// return IntPtr.Size == 4; + return true; // skip everything until fixed + } + } +} \ No newline at end of file diff --git a/tests/introspection/Mac/MacApiProtocolTest.cs b/tests/introspection/Mac/MacApiProtocolTest.cs new file mode 100644 index 000000000000..a4bab15ef264 --- /dev/null +++ b/tests/introspection/Mac/MacApiProtocolTest.cs @@ -0,0 +1,171 @@ +// +// Test the generated API for common protocol support +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2013 Xamarin Inc. +// + +using System; + +#if XAMCORE_2_0 +using Foundation; +using AppKit; +using CoreImage; +#else +using MonoMac.AppKit; +using MonoMac.CoreImage; +#endif + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + public class MonoMacFixtures : ApiProtocolTest { + + protected override bool Skip (Type type, string protocolName) + { + switch (protocolName) { + case "NSSecureCoding": + switch (type.Name) { + case "NSCachedImageRep": // Not declared in header file + case "NSCIImageRep": + case "NSCustomImageRep": + case "NSEPSImageRep": + case "NSBitmapImageRep": + case "NSImageRep": + case "NSPdfImageRep": + case "AVAssetTrackSegment": // Not declared in header file + case "AVComposition": // Not declared in header file + case "AVMutableComposition": // Not declared in header file + case "AVCompositionTrackSegment": // Not declared in header file + case "MKMapSnapshotOptions": // Not declared in header file + case "NSTextTab": // Not declared in header file + return true; + default: + // CIFilter started implementing NSSecureCoding in 10.11 + if (!Mac.CheckSystemVersion (10, 11) && (type == typeof(CIFilter) || type.IsSubclassOf (typeof(CIFilter)))) + return true; + break; + } + break; + case "NSCopying": + switch (type.Name) { + case "DomNodeFilter": // Not declared in header file + case "MKDirectionsRequest": // Not declared in header file + case "EKObject": // Not declared in header file + case "EKCalendarItem": // Not declared in header file + case "EKSource": // Not declared in header file + case "EKCalendar": // Not declared in header file + case "EKEvent": // Not declared in header file + case "EKReminder": // Not declared in header file + case "ACAccount": // Not declared in header file + return true; + } + break; + case "NSMutableCopying": + switch (type.Name) { + case "EKObject": // Not declared in header file + case "EKCalendarItem": // Not declared in header file + case "EKSource": // Not declared in header file + case "EKStructuredLocation": // Not declared in header file + case "EKAlarm": // Not declared in header file + case "EKCalendar": // Not declared in header file + case "EKEvent": // Not declared in header file + case "EKParticipant": // Not declared in header file + case "EKRecurrenceRule": // Not declared in header file + case "EKReminder": // Not declared in header file + return true; + } + break; + case "NSCoding": + switch (type.Name) { + case "EKObject": // Not declared in header file + case "EKCalendarItem": // Not declared in header file + case "EKSource": // Not declared in header file + case "EKStructuredLocation": // Not declared in header file + case "EKAlarm": // Not declared in header file + case "EKCalendar": // Not declared in header file + case "EKEvent": // Not declared in header file + case "EKParticipant": // Not declared in header file + case "EKRecurrenceRule": // Not declared in header file + case "EKReminder": // Not declared in header file + case "AVAssetTrackSegment": // Not declared in header file + case "AVComposition": // Not declared in header file + case "AVMutableComposition": // Not declared in header file + case "AVCompositionTrackSegment": // Not declared in header file + case "MKMapSnapshotOptions": // Not declared in header file + return true; + } + break; + case "NSWindowRestoration": + switch (type.Name) { + case "NSDocumentController": + // There's a category that implements the NSWindowRestoration protocol for NSDocumentController, + // but that apparently doesn't make conformsToProtocol: return true. + // '@interface NSDocumentController (NSWindowRestoration) ' + return true; + } + break; + case "NSUserInterfaceItemIdentification": + // NSViewController started implementing NSUserInterfaceItemIdentification in 10.10 + if (!Mac.CheckSystemVersion (10, 10) && (type == typeof(NSViewController) || type.IsSubclassOf (typeof (NSViewController)))) + return true; + + break; + case "NSMenuDelegate": + switch (type.Name) { + case "PdfView": + if (!Mac.CheckSystemVersion (10, 10)) + return true; + break; + } + break; + case "NSTextFinderClient": // Not listed in header, nor conformsToProtocol, but works in sample. But it just repondsToSelectors + if (type.Name == "NSTextView") + return true; + break; +#if !XAMCORE_4_0 + case "NSDraggingInfo": + return true; // We have to keep the type to maintain backwards compatibility. +#endif + } + + switch (type.Name) { +#if !XAMCORE_3_0 + case "NSRemoteSavePanel": + case "NSRemoteOpenPanel": + return true; // These two classes don't show up in any documentation. +#endif + } + + switch (type.Namespace) { + case "MonoMac.SceneKit": + case "SceneKit": + return IntPtr.Size == 4; // 64bits should be fine + } + + return base.Skip (type, protocolName); + } + + [Test] + public override void SecureCoding () + { + if (!Mac.CheckSystemVersion (10, 8)) + return; + + base.SecureCoding (); + } + + [Test] + public override void SupportsSecureCoding () + { + if (!Mac.CheckSystemVersion (10,8)) + return; + + base.SupportsSecureCoding (); + } + } +} diff --git a/tests/introspection/Mac/MacApiSelectorTest.cs b/tests/introspection/Mac/MacApiSelectorTest.cs new file mode 100644 index 000000000000..eb733ba9c61c --- /dev/null +++ b/tests/introspection/Mac/MacApiSelectorTest.cs @@ -0,0 +1,818 @@ +// +// Mac specific selector validators +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012 Xamarin Inc. All rights reserved. +// + +using System; +using System.Collections.Generic; +using System.Reflection; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#else +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#endif + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + public class MacApiSelectorTest : CoreSelectorTest { + + static MacApiSelectorTest () + { + Runtime.RegisterAssembly (typeof (NSObject).Assembly); + } + + public MacApiSelectorTest () + { + //LogProgress = true; Don't uncomment this anymore, export API_TEST_LOG_PROGRESS=1 + ContinueOnFailure = true; + } + + protected override bool Skip (Type type) + { + switch (type.FullName) { + case "MonoMac.CIFilter.CIMaskedVariableBlur": // Appears to be missing from 10.11, not documented + case "CIFilter.CIMaskedVariableBlur": + if (Mac.CheckSystemVersion (10, 11)) + return true; + break; + case "MonoMac.Foundation.NSUrlSession": + case "Foundation.NSUrlSession": + case "MonoMac.Foundation.NSUrlSessionTask": + case "Foundation.NSUrlSessionTask": + case "MonoMac.Foundation.NSUrlSessionDataTask": + case "Foundation.NSUrlSessionDataTask": + case "MonoMac.Foundation.NSUrlSessionUploadTask": + case "Foundation.NSUrlSessionUploadTask": + case "MonoMac.Foundation.NSUrlSessionDownloadTask": + case "Foundation.NSUrlSessionDownloadTask": + case "MonoMac.Foundation.NSUrlSessionConfiguration": + case "Foundation.NSUrlSessionConfiguration": + // These classes are available in 32-bit Yosemite, or 32+64bit Mavericks. + if (IntPtr.Size == 4 && !Mac.CheckSystemVersion (10, 10)) + return true; + break; + case "MonoMac.AppKit.NSSharingService": + case "AppKit.NSSharingService": + case "MonoMac.AppKit.NSSharingServicePicker": + case "AppKit.NSSharingServicePicker": + case "MonoMac.Foundation.NSByteCountFormatter": + case "Foundation.NSByteCountFormatter": + case "MonoMac.Foundation.NSUserNotification": + case "Foundation.NSUserNotification": + case "MonoMac.Foundation.NSUserNotificationCenter": + case "Foundation.NSUserNotificationCenter": + case "MonoMac.AVFoundation.AVPlayerItemOutput": + case "AVFoundation.AVPlayerItemOutput": + case "MonoMac.AVFoundation.AVPlayerItemVideoOutput": + case "AVFoundation.AVPlayerItemVideoOutput": + case "MonoMac.Foundation.NSUuid": + case "Foundation.NSUuid": + if (!Mac.CheckSystemVersion (10, 8)) + return true; + break; + } + + switch (type.Namespace) { + // OSX 10.8+ + case "MonoMac.Accounts": + case "Accounts": + case "MonoMac.GameKit": + case "GameKit": + case "MonoMac.Social": + case "Social": + case "MonoMac.StoreKit": + case "StoreKit": + if (!Mac.CheckSystemVersion (10, 8)) + return true; + break; + case "SceneKit": + case "MonoMac.SceneKit": + if (!Mac.CheckSystemVersion (10, 8) || IntPtr.Size != 8) + return true; + break; + // not installed by default + case "MonoMac.Growl": + case "Growl": + return true; + } + + return base.Skip (type); + } + + protected override bool Skip (Type type, string selectorName) + { + switch (selectorName) { +#if !XAMCORE_4_0 + case "xamarinselector:removed:": + return true; +#endif +#if !XAMCORE_3_0 + case "initWithPasteboardPropertyList:ofType:": + // This is a broken binding, but it's an abstract protocol + // method, so there's no way to remove it without breaking + // compat. + return true; +#endif + case "waitUntilExit": + // category, NSTask won't respond -> @interface NSTask (NSTaskConveniences) + if (type.Name == "NSTask") + return true; + break; + case "readInBackgroundAndNotifyForModes:": + case "readInBackgroundAndNotify": + case "readToEndOfFileInBackgroundAndNotifyForModes:": + case "readToEndOfFileInBackgroundAndNotify": + case "acceptConnectionInBackgroundAndNotifyForModes:": + case "acceptConnectionInBackgroundAndNotify": + case "waitForDataInBackgroundAndNotifyForModes:": + case "waitForDataInBackgroundAndNotify": + // category, NSFileHandle won't respond -> @interface NSFileHandle (NSFileHandleAsynchronousAccess) + if (type.Name == "NSFileHandle") + return true; + break; + // initWithPlayerIDs: works (valid handle) and is documented - but does not respond when queried + case "initWithPlayerIDs:": + if (type.Name == "GKLeaderboard") + return true; + break; + // some types had NSCopying added after they were first introduced + case "copyWithZone:": + if (type.Name == "CBPeripheral" && !Mac.CheckSystemVersion (10, 9)) + return true; + break; + case "readingOptionsForType:pasteboard:": + case "writingOptionsForType:pasteboard:": + return true; // Optional selectors on NSPasteboardReading/NSPasteboardWriting + } + + switch (type.Namespace) { + // Notifications seems to follow a pattern were selectors are routed to an internal concrete type + case "MonoMac.Foundation": + case "Foundation": + switch (type.Name) { + // looks like it's routed to (private) NSConcreteUserNotificationCenter + case "NSUserNotificationCenter": + switch (selectorName) { + case "delegate": + case "setDelegate:": + case "scheduledNotifications": + case "setScheduledNotifications:": + case "deliveredNotifications": + return true; + } + break; + // looks like it's routed to (private) NSConcreteUserNotification + case "NSUserNotification": + switch (selectorName) { + case "title": + case "setTitle:": + case "subtitle": + case "setSubtitle:": + case "informativeText": + case "setInformativeText:": + case "actionButtonTitle": + case "setActionButtonTitle:": + case "userInfo": + case "setUserInfo:": + case "deliveryDate": + case "setDeliveryDate:": + case "deliveryTimeZone": + case "setDeliveryTimeZone:": + case "deliveryRepeatInterval": + case "setDeliveryRepeatInterval:": + case "actualDeliveryDate": + case "isPresented": + case "isRemote": + case "soundName": + case "setSoundName:": + case "hasActionButton": + case "setHasActionButton:": + case "activationType": + case "otherButtonTitle": + case "setOtherButtonTitle:": + return true; + } + break; + case "NSFileHandle": //Fails on Lion + case "NSUrlAuthenticationChallenge": + case "NSUrlCredential": + case "NSUrlProtectionSpace": + case "NSAppleEventDescriptor": + if (selectorName == "encodeWithCoder:" && !Mac.CheckSystemVersion (10, 8)) + return true; + break; + case "NSValue": + switch (selectorName) { + case "SCNMatrix4Value": + case "SCNVector3Value": + case "SCNVector4Value": + case "valueWithSCNMatrix4:": + if (IntPtr.Size != 8) + return true; + break; + } + break; + case "NSUrlSession": + switch (selectorName) { + case "delegateQueue": + case "sessionDescription": + case "setSessionDescription:": + case "delegate": + if (Mac.CheckSystemVersion (10, 11)) + return true; + break; + } + break; + case "NSUrlSessionStreamTask": + switch (selectorName) { + case "captureStreams": + case "closeRead": + case "closeWrite": + case "readDataOfMinLength:maxLength:timeout:completionHandler:": + case "startSecureConnection": + case "stopSecureConnection": + case "writeData:timeout:completionHandler:": + if (Mac.CheckSystemVersion (10, 11)) + return true; + break; + } + break; + case "NSUrlSessionTask": + switch (selectorName) { + case "countOfBytesExpectedToReceive": + case "countOfBytesExpectedToSend": + case "countOfBytesReceived": + case "countOfBytesSent": + case "currentRequest": + case "error": + case "originalRequest": + case "response": + case "state": + case "taskDescription": + case "setTaskDescription:": + case "taskIdentifier": + if (Mac.CheckSystemVersion (10, 11)) + return true; + break; + } + break; + case "NSUrlSessionConfiguration": + if (Mac.IsAtLeast (10, 11)) + return true; + break; + } + break; + case "MonoMac.AppKit": + case "AppKit": + switch (type.Name) { +#if !XAMCORE_3_0 // These should be not be marked [Abstract] but can't fix w/o breaking change... + case "NSScrollView": + case "NSTextView": + switch (selectorName) { + case "contentViewAtIndex:effectiveCharacterRange:": + case "didReplaceCharacters": + case "drawCharactersInRange:forContentView:": + case "rectsForCharacterRange:": + case "replaceCharactersInRange:withString:": + case "scrollRangeToVisible:": + case "shouldReplaceCharactersInRanges:withStrings:": + case "stringAtIndex:effectiveRange:endsWithSearchBoundary:": + case "stringLength": + case "allowsMultipleSelection": + case "isEditable": + case "firstSelectedRange": + case "isSelectable": + case "selectedRanges": + case "setSelectedRanges:": + case "string": + case "visibleCharacterRanges": + return true; + } + break; +#endif + case "NSMenuDelegate": + switch (selectorName) { +#if !XAMCORE_3_0 + case "menu:willHighlightItem:": + return true; // bound +#endif + } + break; + case "NSResponder": + switch (selectorName) { + case "smartMagnifyWithEvent:": + case "quickLookWithEvent:": + if (!Mac.CheckSystemVersion (10, 8)) + return true; + break; + } + break; + case "NSViewController": + switch (selectorName) { + case "identifier": // + case "setIdentifier:": + // In Yosemite (but not before) NSViewController implements the NSUserInterfaceItemIdentification + // protocol (which brings a r/w Identifier property). We don't have any way of expressing that + // a type started implementing a protocol in a particular version, so just ignore these selectors. + if (!Mac.CheckSystemVersion (10, 10)) + return true; + break; + } + break; + } + break; + // GameKit seems to follow a pattern were selectors are routed to an internal concrete type + case "MonoMac.GameKit": + case "GameKit": + switch (type.Name) { + case "GKTurnBasedExchange": + switch (selectorName) { + case "completionDate": + case "data": + case "exchangeID": + case "sendDate": + case "timeoutDate": + return true; + } + break; + case "GKTurnBasedExchangeReply": + switch (selectorName) { + case "data": + case "replyDate": + return true; + } + break; + // looks like it's routed to (private) GKDialogController_Concrete + case "GKDialogController": + switch (selectorName) { + case "parentWindow": + case "setParentWindow:": + return true; + } + break; + // looks like it's routed to (private) GKVoiceChat_Concrete + case "GKVoiceChat": + switch (selectorName) { + case "start": + case "stop": + case "setMute:forPlayer:": + case "name": + case "isActive": + case "setActive:": + case "volume": + case "setVolume:": + case "playerStateUpdateHandler": + case "setPlayerStateUpdateHandler:": + case "playerIDs": + return true; + } + break; + // looks like it's routed to (private) GKLeaderboard_Concrete + case "GKLeaderboard": + switch (selectorName) { + case "loadScoresWithCompletionHandler:": + case "timeScope": + case "setTimeScope:": + case "playerScope": + case "setPlayerScope:": + case "maxRange": + case "category": + case "setCategory:": + case "title": + case "range": + case "setRange:": + case "scores": + case "localPlayerScore": + case "groupIdentifier": + case "setGroupIdentifier:": + return true; + } + break; + // looks like it's routed to (private) GKLeaderboard_Concrete + case "GKLocalPlayer": + switch (selectorName) { + case "authenticateWithCompletionHandler:": + case "loadDefaultLeaderboardCategoryIDWithCompletionHandler:": + case "setDefaultLeaderboardCategoryID:completionHandler:": + case "authenticateHandler": + case "setAuthenticateHandler:": + case "loadFriendsWithCompletionHandler:": + case "isAuthenticated": + return true; + } + break; + // looks like it's routed to (private) GKMatch_Concrete + case "GKMatch": + switch (selectorName) { + case "sendData:toPlayers:withDataMode:error:": + case "sendDataToAllPlayers:withDataMode:error:": + case "disconnect": + case "voiceChatWithName:": + case "playerIDs": + case "delegate": + case "setDelegate:": + case "expectedPlayerCount": + return true; + } + break; + // looks like it's routed to (private) GKMatchmater_Concrete + case "GKMatchmaker": + switch (selectorName) { + case "inviteHandler": + case "setInviteHandler:": + case "findMatchForRequest:withCompletionHandler:": + case "findPlayersForHostedMatchRequest:withCompletionHandler:": + case "addPlayersToMatch:matchRequest:completionHandler:": + case "cancel": + case "queryPlayerGroupActivity:withCompletionHandler:": + case "queryActivityWithCompletionHandler:": + return true; + } + break; + } + break; + // Gone in Mavericks + case "MonoMac.StoreKit": + case "StoreKit": + switch (type.Name) { + case "SKPayment": + case "SKMutablePayment": + switch (selectorName) { + case "paymentWithProductIdentifier:": + if (Mac.CheckSystemVersion (10, 9)) + return true; + break; + } + break; + } + break; + case "MonoMac.PdfKit": // Bug 20232 + case "PdfKit": + switch (type.Name) { + case "PdfBorder": // Fails on Lion + case "PdfAnnotation": + if (selectorName == "encodeWithCoder:" && !Mac.CheckSystemVersion (10, 8)) + return true; + break; + case "PdfView": + switch (selectorName) { +#if !XAMCORE_3_0 + case "menu:willHighlightItem:": + return true; +#endif + } + break; + } + break; + case "MonoMac.SceneKit": + case "SceneKit": + switch (type.Name) { + case "SCNGeometryElement": + // Ignore on 10.8 where SCNGeometryPrimitiveType is int (32), but + // on 10.9+ is NSInteger/nint (32/64). SceneKit is next to useless + // on 10.8 anyway. -abock + if (selectorName == "primitiveType" && Mac.CheckSystemVersion (10, 8)) + return true; + // fall through + goto case "SCNCamera"; + case "SCNCamera": + case "SCNGeometry": + case "SCNGeometrySource": + case "SCNLight": + case "SCNMaterial": + case "SCNMaterialProperty": + case "SCNNode": + case "SCNProgram": + case "SCNScene": + case "SCNMorpher": + case "SCNSkinner": + case "SCNConstraint": + case "SCNLevelOfDetail": + // The NSSecureCoding protocol was added to these types in Yosemite, + // and we can't (yet?) describe "type added protocol P in version X.Y" + // with our AvailabilityAttribute, so do this check manually. + if (selectorName == "encodeWithCoder:" && !Mac.CheckSystemVersion (10, 10)) + return true; + break; + } + + switch (type.Name) { + case "SCNGeometry": + // SCNGeometry added the SCNShadable protocol in 10.9, which brings in the 'program' selector. + switch (selectorName) { + case "program": + case "setProgram:": + if (!Mac.CheckSystemVersion (10, 9)) + return true; + break; + } + break; + } + break; + } + return base.Skip (type, selectorName); + } + + static List do_not_dispose = new List (); + + protected override void Dispose (NSObject obj, Type type) + { + switch (type.FullName) { + // FIXME: those crash the application when Dispose is called + case "MonoMac.AVFoundation.AVAudioRecorder": + case "AVFoundation.AVAudioRecorder": + case "MonoMac.Foundation.NSUrlConnection": + case "Foundation.NSUrlConnection": + + // 10.8: + case "MonoMac.Accounts.ACAccount": // maybe the default .ctor is not allowed ? + case "Accounts.ACAccount": + case "MonoMac.Accounts.ACAccountCredential": + case "Accounts.ACAccountCredential": + case "MonoMac.Accounts.ACAccountStore": + case "Accounts.ACAccountStore": + case "MonoMac.Accounts.ACAccountType": + case "Accounts.ACAccountType": + do_not_dispose.Add (obj); + break; + default: + base.Dispose (obj, type); + break; + } + } + + protected override bool CheckResponse (bool value, Type actualType, MethodBase method, ref string name) + { + var declaredType = method.DeclaringType; + + switch (name) { + // NSDraggingDestination protocol + case "concludeDragOperation:": // e.g. NSTokenField + case "draggingEnded:": // e.g. NSMatrix + case "draggingExited:": // e.g. NSTokenField + case "draggingUpdated:": // e.g. NSTokenField + case "performDragOperation:": // e.g. NSTokenField + case "prepareForDragOperation:": // e.g. NSTokenField + case "wantsPeriodicDraggingUpdates": // e.g. NSBrowser - optional, [DefaultValue(true)] if it does not exists + return true; + // NSDraggingSource + case "draggedImage:beganAt:": // e.g. NSTextView + case "draggedImage:endedAt:deposited:": // e.g. NSTableView + case "draggedImage:movedTo:": // e.g. NSCollectionView + case "ignoreModifierKeysWhileDragging": // e.g. NSTextView + case "namesOfPromisedFilesDroppedAtDestination:": // e.g. NSTextView + return true; + // NSAnimatablePropertyContainer + case "animationForKey:": // e.g. NSViewAnimation + case "animator": + case "animations": + case "setAnimations:": + return true; + // NSTypeSetter - Layout Phase Interface (needs to be overridden, not really part of the provided types) + case "willSetLineFragmentRect:forGlyphRange:usedRect:baselineOffset:": + case "shouldBreakLineByWordBeforeCharacterAtIndex:": + case "shouldBreakLineByHyphenatingBeforeCharacterAtIndex:": + case "hyphenationFactorForGlyphAtIndex:": + case "hyphenCharacterForGlyphAtIndex:": + case "boundingBoxForControlGlyphAtIndex:forTextContainer:proposedLineFragment:glyphPosition:characterIndex:": + return true; + // in NSView documentation but defined in NSClipView - no answers to call + case "scrollClipView:toPoint:": + return true; + // IKFilterBrowserPanel ??? not clear why + case "finish:": + return true; + // IKFilterUIView + case "viewForUIConfiguration:excludedKeys:": // [Target] on CIFilter + return true; + // NSDictionaryEnumerator + case "fileModificationDate": + case "fileType": + case "filePosixPermissions": + case "fileOwnerAccountName": + case "fileGroupOwnerAccountName": + case "fileSystemNumber": + case "fileSystemFileNumber": + case "fileExtensionHidden": + case "fileHFSCreatorCode": + case "fileHFSTypeCode": + case "fileIsImmutable": + case "fileIsAppendOnly": + case "fileCreationDate": + case "fileOwnerAccountID": + case "fileGroupOwnerAccountID": + return true; // all [Target] on NSDictionary + // SBObject + case "get": + return true; + + // NSCoder - documented as available in 10.8 + case "allowedClasses": + case "requiresSecureCoding": + return true; + + // NSFileManager + case "ubiquityIdentityToken": // documented in 10.8 + return true; + // NS[Mutable]UrlRequest + case "allowsCellularAccess": // documented in 10.8 + case "setAllowsCellularAccess:": // documented in 10.8 + return true; + // NSString + case "capitalizedStringWithLocale:": // documented in 10.8 + case "lowercaseStringWithLocale:": // documented in 10.8 + case "uppercaseStringWithLocale:": // documented in 10.8 + return true; + // AVVideoComposition + case "isValidForAsset:timeRange:validationDelegate:": // documented in 10.8 + return true; + // AVPlayer + case "setRate:time:atHostTime:": // 10.8+ + case "prerollAtRate:completionHandler:": // 10.8+ + case "cancelPendingPrerolls": // 10.8+ + case "masterClock": // 10.8+ + case "setMasterClock:": // 10.8+ + // NSDateComponents + case "isLeapMonth": // 10.8+ + case "setLeapMonth:": // 10.8+ + // NSFileCoordinator + case "itemAtURL:willMoveToURL:": // 10.8+ + return true; // documented (but does not respond) + + // MonoMac.CoreImage.CIDetector (10.8+) + case "featuresInImage:options:": + // MonoMac.CoreImage.CIFaceFeature (10.8+) + case "hasTrackingID": + case "trackingID": + case "hasTrackingFrameCount": + case "trackingFrameCount": + // MonoMac.CoreImage.CIImage : only in 10.8+ + case "properties": // only documented in header files + case "autoAdjustmentFilters": + case "autoAdjustmentFiltersWithOptions:": + // MonoMac.AVFoundation.AVAssetExportSession (10.8+) + case "asset": + // MonoMac.AVFoundation.AVAssetReaderOutput + case "alwaysCopiesSampleData": + case "setAlwaysCopiesSampleData:": + // MonoMac.AVFoundation.AVAssetTrack + case "isPlayable": + // MonoMac.AVFoundation.AVAudioPlayer (10.8+) + case "enableRate": + case "setEnableRate:": + case "rate": + case "setRate:": + // MonoMac.AVFoundation.AVMutableCompositionTrack + case "insertTimeRanges:ofTracks:atTime:error:": + // MonoMac.AVFoundation.AVPlayerItem + case "addOutput:": + case "removeOutput:": + case "canPlayFastReverse": + case "canPlayFastForward": + case "canPlaySlowForward": + case "canPlayReverse": + case "canPlaySlowReverse": + case "canStepForward": + case "canStepBackward": + case "outputs": + case "timebase": + // MonoMac.CoreAnimation.CAAnimation : only on OSX, added for SceneKit + case "usesSceneTimeBase": + case "setUsesSceneTimeBase:": + if (!Mac.CheckSystemVersion (10, 8)) + return true; + break; + case "initWithString:": + if (declaredType.Name == "NSTextStorage") + return true; + break; + } + + switch (declaredType.Name) { + case "NSUrlSession": + case "Foundation.NSUrlSession": + switch (name) { + case "delegateQueue": + case "sessionDescription": + case "setSessionDescription:": + case "delegate": + if (!Mac.CheckSystemVersion (10, 11)) + return true; + break; + } + break; + case "NSUrlSessionTask": + case "Foundation.NSUrlSessionTask": + switch (name) { + case "countOfBytesExpectedToReceive": + case "countOfBytesExpectedToSend": + case "countOfBytesReceived": + case "countOfBytesSent": + case "currentRequest": + case "error": + case "originalRequest": + case "response": + case "state": + case "taskDescription": + case "setTaskDescription:": + case "taskIdentifier": + case "priority": + case "setPriority:": + if (!Mac.CheckSystemVersion (10, 11)) + return true; + break; + } + break; + case "Foundation.NSUrlSessionStreamTask": + case "NSUrlSessionStreamTask": + switch (name) { + case "captureStreams": + case "closeRead": + case "closeWrite": + case "readDataOfMinLength:maxLength:timeout:completionHandler:": + case "startSecureConnection": + case "stopSecureConnection": + case "writeData:timeout:completionHandler:": + if (!Mac.CheckSystemVersion (10, 11)) + return true; + break; + } + break; + } + +// Console.WriteLine ("{0} {1}", declaredType, name); + return base.CheckResponse (value, actualType, method, ref name); + } + + protected override bool CheckStaticResponse (bool value, Type actualType, Type declaredType, ref string name) + { + switch (name) { + // 10.7 exceptions + + // NSAnimatablePropertyContainer protocol (10.7) -> NSViewAnimation + case "defaultAnimationForKey:": + return true; + + // 10.8 exceptions + + // GKPlayer - documented as available in 10.8 + case "loadPlayersForIdentifiers:withCompletionHandler:": + // SLRequest - documented as available in 10.8 + case "requestForServiceType:requestMethod:URL:parameters:": + // NSDictionary - documented as available in 10.8 + case "dictionaryWithSharedKeySet:": + case "sharedKeySetForKeys:": + // AVMetadataItem - documented as available in 10.8 + case "metadataItemsFromArray:filteredAndSortedAccordingToPreferredLanguages:": + return true; + } + return base.CheckStaticResponse (value, actualType, declaredType, ref name); + } + + protected override bool SkipInit (string selector, MethodBase m) + { + switch (selector) { +#if !XAMCORE_3_0 + // DomEvent + case "initEvent:canBubbleArg:cancelableArg:": + // DomOverflowEvent + case "initOverflowEvent:horizontalOverflow:verticalOverflow:": + // DomUIEvent + case "initUIEvent:canBubble:cancelable:view:detail:": + // DomKeyboardEvent + case "initKeyboardEvent:canBubble:cancelable:view:keyIdentifier:keyLocation:ctrlKey:altKey:shiftKey:metaKey:altGraphKey:": + case "initKeyboardEvent:canBubble:cancelable:view:keyIdentifier:keyLocation:ctrlKey:altKey:shiftKey:metaKey:": + // DomMouseEvent + case "initMouseEvent:canBubble:cancelable:view:detail:screenX:screenY:clientX:clientY:ctrlKey:altKey:shiftKey:metaKey:button:relatedTarget:": + // DomWheelEvent + case "initWheelEvent:wheelDeltaY:view:screenX:screenY:clientX:clientY:ctrlKey:altKey:shiftKey:metaKey:": + // QTMovie + case "movieWithTimeRange:error:": + case "initWithQuickTimeMedia:error:": + // NSAppleEventDescriptor + case "initListDescriptor": + case "initRecordDescriptor": + // NSAnimation + case "initWithDuration:animationCurve:": + return true; +#endif + // NSImage + case "initWithDataIgnoringOrientation:": + var mi = m as MethodInfo; + return mi != null && !mi.IsPublic && mi.ReturnType.Name == "IntPtr"; + default: + return base.SkipInit (selector, m); + } + } + } +} diff --git a/tests/introspection/Mac/MacApiSignatureTest.cs b/tests/introspection/Mac/MacApiSignatureTest.cs new file mode 100644 index 000000000000..32ba458e193d --- /dev/null +++ b/tests/introspection/Mac/MacApiSignatureTest.cs @@ -0,0 +1,234 @@ +// +// Test the generated API selectors against typos or non-existing cases +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013 Xamarin Inc. All rights reserved. +// + +using System; +using System.Reflection; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#else +using MonoMac.Foundation; +using MonoMac.ObjCRuntime; +#endif + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class MacSignatureTest : ApiSignatureTest { + + static MacSignatureTest () + { + Runtime.RegisterAssembly (typeof (NSObject).Assembly); + } + + public MacSignatureTest () + { + ContinueOnFailure = true; + //LogProgress = true; + } + + protected override bool Skip (Type type, MethodBase method, string selector) + { + switch (type.Namespace) { + case "MonoMac.GameKit": + case "GameKit": + case "MonoMac.StoreKit": + case "StoreKit": + if (!Mac.CheckSystemVersion (10, 8)) + return true; + break; + case "MonoMac.SceneKit": + case "SceneKit": + // SceneKit is half-baked at best, and they broke compatibility significantly + // from Mountain Lion to Mavericks, so just ignore all problems there. + if (!Mac.CheckSystemVersion (10, 9)) + return true; + break; + } + + // Bug 20232 - This is a hack. + if (selector == "geometryElementWithData:primitiveType:primitiveCount:bytesPerIndex:") + return true; + + switch (type.Name) { + case "AVPlayerItemOutput": + case "AVPlayerItemVideoOutput": + case "NSSharingService": + case "NSSharingServicePicker": + case "NSUserNotification": + case "NSUserNotificationCenter": + case "NSUuid": + return !Mac.CheckSystemVersion (10, 8); + + case "CALayer": + case "CAEmitterLayer": + case "CAGradientLayer": + case "CAOpenGLLayer": + case "CAReplicatorLayer": + case "CAScrollLayer": + case "CAShapeLayer": + case "CATextLayer": + case "CATiledLayer": + case "CATransformLayer": + case "QTCaptureLayer": + case "QTMovieLayer": + case "QCCompositionLayer": + case "AVCaptureVideoPreviewLayer": + case "AVPlayerLayer": + case "SCNLayer": + switch (selector) { + // CAGradientLayer 'instance MonoMac.CoreAnimation.CAConstraint[] get_Constraints()' selector: constraints == @?@: + case "constraints": + // CAGradientLayer 'instance Void set_Constraints(MonoMac.CoreAnimation.CAConstraint[])' selector: setConstraints: == v@:@? + case "setConstraints:": + return true; + } + break; + case "SCNSkinner": + return !Mac.CheckSystemVersion (10, 9); + case "NSGradient": + switch (selector) { + case "initWithColorsAndLocations:": // variable length parameters ... + case "initWithColors:atLocations:colorSpace:": // void * -> nfloat [] (internal) + return true; + } + break; + case "AVAudioIONode": + case "AVAudioUnit": + switch (selector) { + case "audioUnit": // ^{ComponentInstanceRecord=[1l], tested to work in an apitest + return true; + } + break; + } + return base.Skip (type, method, selector); + } + + protected override int Size (Type t, bool simd = false) + { + switch (t.FullName) { + case "GameKit.GKGameCenterViewControllerState": + case "AppKit.NSOpenGLContextParameter": + // NSOpenGLContextParameter and GKGameCenterViewControllerState are anonymous enums in 10.9, but an NSInteger in 10.10. + if (IntPtr.Size == 8 && !Mac.CheckSystemVersion (10, 10)) + return 4; + break; + } + + return base.Size (t, simd); + } + + protected override bool IsValidStruct (Type type, string structName) + { + switch (structName) { + case "_NSPoint": +#if XAMCORE_2_0 + return type.FullName == "CoreGraphics.CGPoint"; +#else + return type.FullName == "System.Drawing.PointF"; +#endif + case "_NSRect": +#if XAMCORE_2_0 + return type.FullName == "CoreGraphics.CGRect"; +#else + return type.FullName == "System.Drawing.RectangleF"; +#endif + case "_NSSize": +#if XAMCORE_2_0 + return type.FullName == "CoreGraphics.CGSize"; +#else + return type.FullName == "System.Drawing.SizeF"; +#endif + case "_SCNVector3": + return type.Name == "SCNVector3"; + case "_SCNVector4": + return type.Name == "SCNVector4"; + // CIImage 'static MonoMac.CoreImage.CIImage FromImageBuffer(MonoMac.CoreVideo.CVImageBuffer)' selector: imageWithCVImageBuffer: == @12@0:4^{__CVBuffer=}8 + // AVAssetWriterInputPixelBufferAdaptor 'instance Boolean AppendPixelBufferWithPresentationTime(MonoMac.CoreVideo.CVPixelBuffer, CMTime)' selector: appendPixelBuffer:withPresentationTime: == c36@0:4^{__CVBuffer=}8{?=qiIq}12 + case "__CVBuffer": + return type.Name == "CVImageBuffer" || type.Name == "CVPixelBuffer";; + case "CATransform3D": + return type.Name == "CATransform3D" || type.Name == "SCNMatrix4"; + case "SCNVector4": + return type.Name == "SCNVector4" || type.Name == "SCNQuaternion"; // "SCNQuaternion is a SCNVector 3, then a nfloat, so same structure + } + return base.IsValidStruct (type, structName); + } + + // only handle exception here (to return true) otherwise call base to deal with it + protected override bool Check (string encodedType, Type type) + { + switch (encodedType) { + case "^{OpaqueSecTrustRef=}": + // On 10.7 and 10.8: + // [FAIL] Signature failure in MonoMac.Foundation.NSUrlCredential initWithTrust: Parameter 'trust' (#1) is encoded as '^{OpaqueSecTrustRef=}' and bound as 'MonoMac.Security.SecTrust' + return type.Name == "SecTrust" || type.FullName == "System.IntPtr"; + } + return base.Check (encodedType, type); + } + + // only handle exception here (to return true) otherwise call base to deal with it + // `caller` is provided to make it easier to detect "special" cases + protected override bool Check (char encodedType, Type type) + { + switch (encodedType) { + case 'i': + switch (type.FullName) { + case "System.nuint": + case "System.UInt32": + // sign-ness mis-binding, not critical + // Signature failure in MonoMac.AppKit.NSViewController presentViewController:asPopoverRelativeToRect:ofView:preferredEdge:behavior: Parameter 'preferredEdge' (#4) is encoded as 'i' and bound as 'System.UInt32' + return true; + case "GameKit.GKGameCenterViewControllerState": + case "AppKit.NSOpenGLContextParameter": + // NSOpenGLContextParameter and GKGameCenterViewControllerState are anonymous enums in 10.9, but an NSInteger in 10.10. + if (IntPtr.Size == 8 && !Mac.CheckSystemVersion (10, 10)) + return true; + break; + } + break; + // unsigned 32 bits + case 'I': + switch (type.FullName) { + case "System.Int32": + // sign-ness mis-binding, several of them (not critical) + // NSActionCell 'instance Int32 get_MnemonicLocation()' selector: mnemonicLocation == I8@0:4 + // NSPathCell 'instance Int32 get_MnemonicLocation()' selector: mnemonicLocation == I8@0:4 + // SCNText 'instance Void InsertMaterial(MonoMac.SceneKit.SCNMaterial, Int32)' selector: insertMaterial:atIndex: == v16@0:4@8I12 + return true; + } + break; + // unsigned 32 bits + case 'L': + switch (type.FullName) { + // sign-ness mis-binding (not critical) e.g. + // CAMediaTimingFunction 'instance Void GetControlPointAtIndex(Int32, IntPtr)' selector: getControlPointAtIndex:values: == v16@0:4L8[2f]12 + case "System.Int32": + return true; + } + break; + // unsigned 64 bits + case 'Q': + switch (type.FullName) { + // sign-ness mis-binding (not critical) e.g. + // NSEvent 'instance Int64 get_UniqueID()' selector: uniqueID == Q8@0:4 + case "System.Int64": + return true; + } + break; + } + return base.Check (encodedType, type); + } + } +} diff --git a/tests/introspection/Mac/MacApiWeakPropertyTest.cs b/tests/introspection/Mac/MacApiWeakPropertyTest.cs new file mode 100644 index 000000000000..904a20f0c0f6 --- /dev/null +++ b/tests/introspection/Mac/MacApiWeakPropertyTest.cs @@ -0,0 +1,26 @@ +using System; + +#if XAMCORE_2_0 +using Foundation; +#else +using MonoMac.Foundation; +#endif + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + public class MacApiWeakPropertyTest : ApiWeakPropertyTest { + protected override bool Skip (Type type) + { + switch (type.Name) { + case "CATextLayer": // CATextLayer.WeakFont is done correctly by hand + return true; + case "NSAttributedStringDocumentAttributes": // NSAttributedStringDocumentAttributes.WeakDocumentType is done by hand, not a binding + return true; + } + return base.Skip (type); + } + } +} diff --git a/tests/introspection/Mac/MacCoreImageFiltersTest.cs b/tests/introspection/Mac/MacCoreImageFiltersTest.cs new file mode 100644 index 000000000000..caaa27551348 --- /dev/null +++ b/tests/introspection/Mac/MacCoreImageFiltersTest.cs @@ -0,0 +1,47 @@ +// +// Test the generated API for all Mac CoreImage filters +// +// Authors: +// Sebastien Pouliot +// Alex Soto +// +// Copyright 2013, 2015 Xamarin Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + public class MacCoreImageFiltersTest : ApiCoreImageFiltersTest + { + protected override bool Skip (string nativeName) + { + switch (nativeName) { + case "CIMaskedVariableBlur": // Appears removed in 10.11 but not documented + if (Mac.CheckSystemVersion (10, 11)) + return true; + return false; + case "CICMYKHalftone": // Renamed as CICmykHalftone + return true; + default: + return base.Skip (nativeName); + } + } + } +} + diff --git a/tests/introspection/Mac/introspection-mac.csproj b/tests/introspection/Mac/introspection-mac.csproj new file mode 100644 index 000000000000..f940c1ce7403 --- /dev/null +++ b/tests/introspection/Mac/introspection-mac.csproj @@ -0,0 +1,124 @@ + + + + Debug + x86 + {FD385098-B3FD-4331-92BF-CC1F918E3334} + {42C0BBD9-55CE-4FC1-8D90-A7348ABAFB23};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + dontlink + dontlink-mac + Resources + v4.5 + + + true + full + false + bin\x86\Debug + DEBUG;MONOMAC + prompt + 4 + false + false + Mac Developer + false + false + false + false + x86 + + + true + bin\x86\Release + MONOMAC + prompt + 4 + false + true + Developer ID Application + true + false + true + false + SdkOnly + x86 + + + + + + + + + + + + + + + + + + + + + ApiBaseTest.cs + + + ApiClassPtrTest.cs + + + ApiCoreImageFiltersTest.cs + + + ApiCtorInitTest.cs + + + ApiFieldTest.cs + + + ApiPInvokeTest.cs + + + ApiProtocolTest.cs + + + ApiSelectorTest.cs + + + ApiSignatureTest.cs + + + ApiStructTest.cs + + + ApiTypoTest.cs + + + ApiWeakPropertyTest.cs + + + CoreSelectorTest.cs + + + EnvironmentVariable.cs + + + PlatformInfo.cs + + + MacTestMain.cs + + + + + {D12F0F7B-8DE3-43EC-BA49-41052D065A9B} + GuiUnit_NET_4_5 + + + + + + + diff --git a/tests/introspection/PlatformInfo.cs b/tests/introspection/PlatformInfo.cs new file mode 100644 index 000000000000..f569f5f4b183 --- /dev/null +++ b/tests/introspection/PlatformInfo.cs @@ -0,0 +1,151 @@ +// +// PlatformInfo.cs: info about the host platform +// and AvailabilityBaseAttribute extensions for tests +// +// Author: +// Aaron Bockover +// +// Copyright 2015 Xamarin Inc. All rights reserved. + +using System; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; + +#if XAMCORE_2_0 +using ObjCRuntime; +using Foundation; +#if !MONOMAC +using UIKit; +#endif +#elif MONOMAC +using MonoMac.ObjCRuntime; +using MonoMac.Foundation; +#else +using MonoTouch.ObjCRuntime; +using MonoTouch.Foundation; +using MonoTouch.UIKit; +#endif + +namespace Introspection +{ + public sealed class PlatformInfo + { + static PlatformInfo GetHostPlatformInfo () + { + string name; + string version; +#if __TVOS__ || __IOS__ + name = UIDevice.CurrentDevice.SystemName; + version = UIDevice.CurrentDevice.SystemVersion; +#elif __WATCHOS__ + name = WatchKit.WKInterfaceDevice.CurrentDevice.SystemName; + version = WatchKit.WKInterfaceDevice.CurrentDevice.SystemVersion; +#elif MONOMAC + using (var plist = NSDictionary.FromFile ("/System/Library/CoreServices/SystemVersion.plist")) { + name = (NSString)plist ["ProductName"]; + version = (NSString)plist ["ProductVersion"]; + } +#else +#error Unknown platform +#endif + name = name?.Replace (" ", String.Empty)?.ToLowerInvariant (); + + var platformInfo = new PlatformInfo (); + + if (name != null && name.StartsWith ("mac", StringComparison.Ordinal)) + platformInfo.Name = PlatformName.MacOSX; + else if (name != null && (name.StartsWith ("ios", StringComparison.Ordinal) || name.StartsWith ("iphoneos", StringComparison.Ordinal))) + platformInfo.Name = PlatformName.iOS; + else if (name != null && name.StartsWith ("tvos", StringComparison.Ordinal)) + platformInfo.Name = PlatformName.TvOS; + else if (name != null && name.StartsWith ("watchos", StringComparison.Ordinal)) + platformInfo.Name = PlatformName.WatchOS; + else + throw new FormatException ($"Unknown product name: {name}"); + + platformInfo.Version = Version.Parse (version); + + if (IntPtr.Size == 4) + platformInfo.Architecture = PlatformArchitecture.Arch32; + else if (IntPtr.Size == 8) + platformInfo.Architecture = PlatformArchitecture.Arch64; + + return platformInfo; + } + + public static readonly PlatformInfo Host = GetHostPlatformInfo (); + + public PlatformName Name { get; private set; } + public PlatformArchitecture Architecture { get; private set; } + public Version Version { get; private set; } + + public bool IsMac => Name == PlatformName.MacOSX; + public bool IsIos => Name == PlatformName.iOS; + public bool IsArch32 => Architecture.HasFlag (PlatformArchitecture.Arch32); + public bool IsArch64 => Architecture.HasFlag (PlatformArchitecture.Arch64); + + PlatformInfo () + { + } + } + + public static class AvailabilityExtensions + { + public static bool IsAvailableOnHostPlatform (this ICustomAttributeProvider attributeProvider) + { + return attributeProvider.IsAvailable (PlatformInfo.Host); + } + + public static bool IsAvailable (this ICustomAttributeProvider attributeProvider, PlatformInfo targetPlatform) + { + return attributeProvider + .GetCustomAttributes (true) + .OfType () + .IsAvailable (targetPlatform); + } + + public static bool IsAvailableOnHostPlatform (this IEnumerable attributes) + { + return attributes.IsAvailable (PlatformInfo.Host); + } + + public static bool IsAvailable (this IEnumerable attributes, PlatformInfo targetPlatform) + { + // always "available" from a binding perspective if + // there are no explicit annotations saying otherwise + var available = true; + + foreach (var attr in attributes) { + if (attr.Platform != targetPlatform.Name) + continue; + + switch (attr.AvailabilityKind) { + case AvailabilityKind.Introduced: + if (attr.Version != null) + available &= targetPlatform.Version >= attr.Version; + + if (attr.Architecture != PlatformArchitecture.None && + attr.Architecture != PlatformArchitecture.All) + available &= attr.Architecture.HasFlag (targetPlatform.Architecture); + break; + case AvailabilityKind.Deprecated: + case AvailabilityKind.Obsoleted: + if (attr.Version != null) + available &= targetPlatform.Version < attr.Version; + // FIXME: handle architecture-level _un_availability? + // we didn't do this with the old AvailabilityAttribute... + break; + case AvailabilityKind.Unavailable: + available = false; + break; + } + + if (!available) + return false; + } + + return available; + } + } +} diff --git a/tests/introspection/iOS/AppDelegate.cs b/tests/introspection/iOS/AppDelegate.cs new file mode 100644 index 000000000000..b2067a32ef95 --- /dev/null +++ b/tests/introspection/iOS/AppDelegate.cs @@ -0,0 +1,40 @@ +#if !__WATCHOS__ +using System; +using System.Reflection; +#if XAMCORE_2_0 +using Foundation; +using UIKit; +#else +using MonoTouch.Foundation; +using MonoTouch.UIKit; +#endif +using MonoTouch.NUnit.UI; + +namespace Introspection { + + [Register ("AppDelegate")] + public partial class AppDelegate : UIApplicationDelegate + { + static public TouchRunner Runner { get; private set; } + + public override UIWindow Window { get; set; } + + public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) + { + // create a new window instance based on the screen size + Window = new UIWindow (UIScreen.MainScreen.Bounds); + Runner = new TouchRunner (Window); + + // tests can be inside the main assembly + Runner.Add (Assembly.GetExecutingAssembly ()); + + Window.RootViewController = new UINavigationController (Runner.GetViewController ()); + + // make the window visible + Window.MakeKeyAndVisible (); + + return true; + } + } +} +#endif // !__WATCHOS__ diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/Contents.json b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/Contents.json new file mode 100644 index 000000000000..6be52c8f7640 --- /dev/null +++ b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/Contents.json @@ -0,0 +1,221 @@ +{ + "images": [ + { + "size": "29x29", + "scale": "1x", + "idiom": "iphone" + }, + { + "size": "29x29", + "scale": "2x", + "idiom": "iphone" + }, + { + "size": "29x29", + "scale": "3x", + "idiom": "iphone" + }, + { + "size": "40x40", + "scale": "2x", + "idiom": "iphone" + }, + { + "size": "40x40", + "scale": "3x", + "idiom": "iphone" + }, + { + "filename": "icon-app-57.png", + "size": "57x57", + "scale": "1x", + "idiom": "iphone" + }, + { + "filename": "icon-app-57@2x.png", + "size": "57x57", + "scale": "2x", + "idiom": "iphone" + }, + { + "filename": "icon-app-60@2x.png", + "size": "60x60", + "scale": "2x", + "idiom": "iphone" + }, + { + "filename": "icon-app-60@3x.png", + "size": "60x60", + "scale": "3x", + "idiom": "iphone" + }, + { + "size": "29x29", + "scale": "1x", + "idiom": "ipad" + }, + { + "size": "29x29", + "scale": "2x", + "idiom": "ipad" + }, + { + "size": "40x40", + "scale": "1x", + "idiom": "ipad" + }, + { + "size": "40x40", + "scale": "2x", + "idiom": "ipad" + }, + { + "size": "50x50", + "scale": "1x", + "idiom": "ipad" + }, + { + "size": "50x50", + "scale": "2x", + "idiom": "ipad" + }, + { + "filename": "icon-app-83.5@2x.png", + "size": "83.5x83.5", + "scale": "2x", + "idiom": "ipad" + }, + { + "filename": "icon-app-72.png", + "size": "72x72", + "scale": "1x", + "idiom": "ipad" + }, + { + "filename": "icon-app-72@2x.png", + "size": "72x72", + "scale": "2x", + "idiom": "ipad" + }, + { + "filename": "icon-app-76.png", + "size": "76x76", + "scale": "1x", + "idiom": "ipad" + }, + { + "filename": "icon-app-76@2x.png", + "size": "76x76", + "scale": "2x", + "idiom": "ipad" + }, + { + "role": "notificationCenter", + "size": "24x24", + "subtype": "38mm", + "scale": "2x", + "idiom": "watch" + }, + { + "role": "notificationCenter", + "size": "27.5x27.5", + "subtype": "42mm", + "scale": "2x", + "idiom": "watch" + }, + { + "role": "companionSettings", + "size": "29x29", + "scale": "2x", + "idiom": "watch" + }, + { + "role": "companionSettings", + "size": "29x29", + "scale": "3x", + "idiom": "watch" + }, + { + "role": "appLauncher", + "size": "40x40", + "subtype": "38mm", + "scale": "2x", + "idiom": "watch" + }, + { + "role": "longLook", + "size": "44x44", + "subtype": "42mm", + "scale": "2x", + "idiom": "watch" + }, + { + "role": "quickLook", + "size": "86x86", + "subtype": "38mm", + "scale": "2x", + "idiom": "watch" + }, + { + "role": "quickLook", + "size": "98x98", + "subtype": "42mm", + "scale": "2x", + "idiom": "watch" + }, + { + "size": "16x16", + "scale": "1x", + "idiom": "mac" + }, + { + "size": "16x16", + "scale": "2x", + "idiom": "mac" + }, + { + "size": "32x32", + "scale": "1x", + "idiom": "mac" + }, + { + "size": "32x32", + "scale": "2x", + "idiom": "mac" + }, + { + "size": "128x128", + "scale": "1x", + "idiom": "mac" + }, + { + "size": "128x128", + "scale": "2x", + "idiom": "mac" + }, + { + "size": "256x256", + "scale": "1x", + "idiom": "mac" + }, + { + "size": "256x256", + "scale": "2x", + "idiom": "mac" + }, + { + "size": "512x512", + "scale": "1x", + "idiom": "mac" + }, + { + "size": "512x512", + "scale": "2x", + "idiom": "mac" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/Icon-app-60@3x.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/Icon-app-60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..45342a7513b6260dcd80e17e56cc1f24c60053c6 GIT binary patch literal 5100 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 Wj@>R+sJ%Sj(HI+=88qlQ#s3EegqAJ< literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-57.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-57.png new file mode 100644 index 0000000000000000000000000000000000000000..ce1d9df94d4fb7bc08771ca49e02cdf9f63e31e3 GIT binary patch literal 1618 zcmV-Y2CeytP)Px*3`s;mRA>e5Sy^mURT%#6z0)al84HDOv~(L=Txg-VKWV~)lK7x6jT$19s?iu< z1f$dxZ7dqW7h^Ok6ij2(m}rcN@L)oGK;yklg^#9{pb76ckch6GnE2lSmq`#bAEzelH_txIjLk)$pl(~Y?FNN??Lp<`t0IZI-a&}{~Yk{xxS@sCTnbw?3uob5C0jB+cpiy9#m7I zXg!QB&z0~d)8B28Z1}wwUX5RfI7<3e6@H%&0l)rs6aA=VAf@Zda|J=JKX&oo z@aDzup&<0e=^pUBR?HH~1Lp=XHm|=8dG+5sdjZ~sty))+hpd!qQ}GtgQv9gDwNPN@ ze*4KM6VfuyonxwuwCM9NjiCjne=i;Z!gDIx8NUSZpy`{SVrQFfkWQ zFS|%hmqJRB50~u6Qwu6``}-ZSBQ*OAI8w0p*G@1FGiHipYv(B1Jaf@iT$r7=n8z>U z?bE?6mYJfU&P{5nKJ0Yog3E00{4oHJPk-w#xC=gr=sAxUpPV1Ot~yr1FiDkG@4%lI z4G|1Y%3JJ<-f^@~&WNgAbh{{U%A{hED0BU1)UNj~hWvz{Vu#R4=pZc&<1uQ6NlsH_ zn=-oMVY92Uf}`hy@1~2?J9xJn{A6qG8ii{5N(REAg7FwN!z42ZSf;~p_r>`Yzlt3j zg35Ua*zTV@!B4jBL}aFSdiU*xU_3_6FiCc}osxQ$E7cGvP7@qOU)o$I zuy7)8>AVDq-l-#E&qGFu0zLb7;}Z=*MW@`cIT(qdGfNj4|_Jnj|~lv#}6s z!j5T?6EdJzs!QM`GHflR;$+w{kaOrH9n%gioQSyJUh=8;Zt~V&L&w0EYsw<0GE}xi zk`sAjb&>uxD&WV%#cKrsR_hQQA|i7k=g^j}5%4XA?V)w6#53|E6l`AIT)KFGi0l)q zZ0py$$A4(Y$?=&b1VZm5Nh5A5telnw2?R-UAFY0T*Sv34Dn8#@rRBm3~l>81d)AUOp+n3svIh1q6@YW9x{N%s8OredT?bnB;W zX4Qm(loQh>`VHw0d%-3gL-b=tc+VK$b62LIiE?Lr{;O3Iw}199Y+HFU2JaiDId0qa zhGC=uBuP?ZQ4+E$sboURrU5#sq{gBoWK~khgp^GKbW%x;MM=o2|AmtO0n;5kf!5v^ QQ~&?~07*qoM6N<$f|#ljUH||9 literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-57@2x.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-57@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d34d9c694d3f26c7d29afc045f31a502a91a06d2 GIT binary patch literal 3206 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 PcPs!Hb1P&$!YlPZ`C{@6 literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-60@2x.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4409624b29d98e118ba8fba1f9ab1c23f2ffeb97 GIT binary patch literal 3357 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 literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-72.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-72.png new file mode 100644 index 0000000000000000000000000000000000000000..9a77ea2773124b5e28e2c0fc2fa6a2c6fc2aacff GIT binary patch literal 1820 zcmV+%2jlpOP)Px*)=5M`RCodHnpt6EXT^6T%C@#J<#6 zY9FjYcu~Z_L)!=2gv)zlz$Z;KF^Eciv5G)!6|87WYukggMS3~(a*p4(bWhLjnLV@H znQeHONt&}eGduI`Z~i;;-`RTNm_Q{<0$$4!RiF`2fH*=>fD|AO0Zy?}kOIUZz$sP= zQh+!FIK@gq3J`|?r&uXS0pbwg6e|TOKpX;`Vx=Gjh(mx=?B|pV7sqfvuJzg=d^&Ik z#_lg*dmh0y<50N95Bn4Dhwhg^d%Rxwe0UNrj!X(7NPoF&fauZs7#}T<&o50m z=360E9=|#W)R$YyH9%ecqi|zt-ZeM`gp_n+dLFv|9CM2gxB_TqVG&w;hqXt`waE2` z5mIa42vDDHBv$}+_71`A`M9g<(P5B^{+*9O=WqY$SyF$c0~(v1gERe+)ltt93YxIb z{1JgjbY3bPYD_wylfV28QEZmAq{kK)A-1rP__OoPlIj?)!!}sgMbTfK#0gt=lInx{ zCZ=KU*S`Yz11W&$CI{=DGQ?kZp%;4Y-cPBkS0WHk=LF&0o*F$%gHv(-C-C|i9v9(% z`BDv3=VT`8iylZ-(6P&Z0az^Sq$smzX{y}-aSKIgH->%&jIATr` z)jvNt4&l}AqB@@qO<1pvdIOB#C@zkt1XUyi=({o8i*X1iaUbYeKDsiH zIHiN8+A=s)Q)0;b@bXPdZ)K>+I>Fe!kKALG*v=CI6ic-)wmY_4(U~?=TV2EnUnB_u z+Lga<<$dE^^Zt$s!}aYr;kWl0-^!0X`6$5RLaI+PTxoHFa9+sIwkWihEd;2(rW7*b z?3c%M-P1}{SDp(s;pKOxOCuA|GZBR!$7kS&vAc=Osm|-AVW!(oRI)h8fH=JQnDLRd zsA`!l1gI=42nRP6XinI&2Sz~<18>=0ZYXI-pX2eO6UVu!4L948Q_B;T5Cn$XPOfA+ zCU^eErhF*PTw^M6b}9sjx@z272Dv^OV0+Ix1zx|U01ASEM5MZUXu_uzu4iJ_prXRH z8Bo6&2Lc~UJBeZm`@QfszQ%|qVL;gdA2e1M+X|in&kJ~=q1q_>2kJ@MLqbSq6*b_^ z<_A3X1_JwOtS$nIO*9Duq5uw5mB7Z3pC3F1-ds}*A^&pV$?DN>hNU99rg>?5M6bvC zr9s#j3c!KQMXX}Sc~SuRy&ib)@$$4PqQI*%1F(Nnp&`f=_2{Jx7465HuF49e9|-KH zW$Ol@m}Dd=fGCi?W$U%Ka++h92?IZj6La#X;_lH&ZRKK_O_qx2+QZu`EEfeD1lmKQ zSY#z>fGD7&J1Q}F_OegG?=H?U#NEF1X^3Dj6XsK$enGOdJ#24rFyRwWy2?uztu|zbZaUKd%n5` zb6)p8IVT7w9RyIh7hm2c?0b@$)DERSV$|YF&7(OmC+DQFgAz<3t54~Gs1q`eVIMvk z`eVWBSyCSLL8h=#f+=K$5vFGP0YLVGqpZgHzq4j z`Z8}0Y#z5AKlu43oWnin8Ep&F!W5b>OmiOcd0=0~dN_jHAOT6Q6jt524oL5qMtusu zQ!U#>y~Nos;myKT%WM>#wPL^assXYe(!*8LwMqKny3LhGqX2Q(DL@JkhXAKoDM$h0 z5a1Lm1t~xr0-R!{AO(m+fK#j#qyTXUaEg_J6d(=(PO(xD2hjgQ{=bE1R^Rym0000< KMNUMnLSTYI?@J~C literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-72@2x.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-72@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..32f57d7d89dad22e1acb84091fa81351ca847528 GIT binary patch literal 4093 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 F{Re?zo!I~Y literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-76.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-76.png new file mode 100644 index 0000000000000000000000000000000000000000..12db0c47cc4ec7d9e36549598d7be77ba413e87b GIT binary patch literal 2082 zcmV+-2;KLIP)Px++(|@1RCodHnrUoQRTO~Fd$Y8imSyO4x^L`IpoO^nU`zO=M1L4CXfPo$LLe$C zB8degsFg$_ng)dk!4QK%qlv+dKdyuyMg)q~R-moZ(rsud&~-YS=S=(Fn}L~mbKg=E za!)duH}Bqa@44SQ_uO;u8zGDWTv8?=rd*R(j1b_!7#)EFgRFjnUt#(^;sV64tP zj00mNz*wDo7zf5kfU!FFFb<570AqFTVH_AE0mkaw!#FTT0*uwUhcN=PGS=5z{ov&` z__XB)bdChD4MB4|v5H~HOS8iIau>X`uq3v~q+h~B98vE+*9^y7dO@&QKoE?AHAaL^ z*u%jftS_Ag`yQHM5+G!!s=8pZ=c(3*#XaHQdSykf)dnFg%a=ZD(HE}Aoj z8LQTiAc}DCpDyr@_|>XvE;kKW4Nk@WV0c2jOBy|S*d%E%STu3De5;e+l)y=X?uQ|7NW!T| zKtq@}g#v-G4_?zfHDS@Csd@R%D13GeW2nJmXyV%M55mgt>!3F{mLJ8lm0X1ZlqRQ|(t+&LrwOyyM8 zhYxOlT`T=GObi2d<@OL}^avu!AR<;{`3DUhFciSijLXKk1(0tS<4#TT6t_))&GU<- z>M#-v!Ta?cDfM;2(+iEa24!8n7lr|&Kpzy<_lor7dvO2#VZD-IrdvdKwW2Vtm(f1) z6)elJDyAMnU9Ufs)WZl2^%X*!cAsm}%SqN(tdMW9UwnsC>}=1V>Hy@HaUe&pd7*oF zRKB&gJO}1y*<-wnylYOD4W63rmh1IkLi};l4R!At*C1%W_YK1-59$~ox`EO3sJYa} zlt$1XMnHsjqv8wQtFA1LoIFV5BJX;AQ3;4xCdvLf4-AFIyhpmH_DyNVJ7^=>s#kOa zqv_G^Q=cC97>W?S!sNCgD!wewn+hv)vLGA^MLx^29k8l!nygB3@{3mXgqR*i=V%ye z@k~yy=mOS0=z~KzwNwLr94l!MVa&>D3l%N9s!Biz;evplor}w&i=YNiBPb?m6728D z)o$?g4{K7Flym{Bt#1QglKe^PB+)l*V}8Tf_e+Ozjx}d$COlc}gf&G|p~9IdtDePk zwV%BMsmDoKbL@g1(5PU6+WPjpO4xqt%IMB``!#u2w21_5AI6sz`A#`jy;fBQ0gPXg zQ1Gw898dRl3!$Cy>f2-L0wxW}=sFf`hMNpU) ze;+9K67K>Bum)GddAKS{LPtZ*}y8nz7j;bfC?L^FGe1J;#Hi{xmMPAcE@aPsW} zyttq^mFh|B=mtjnz+H=CGxVfAVj&G69gk~vR4OlDeVB#U{*6mMf|7*1thS*uCPUwj zIu5j&WolCFqZmlG>J|MhparW-T(A^lQObirV9()H&dspP_8-661s#};lV?dn*WLaw z9BWi^Cs&#cHqFRMISi0Z4?8p9@lu!6tgdfEfRP1zmz0489qD1>mqM zTb#qVAMH!LqvB+8v?V=j zr~FIyM1(=xqv+TbZ-4}vMUP&x?5iq*^|SKhHK+NWp&mw7ti!{;#Z%G~K79g1FD^u@ zb?ieq7v5777CnNyV6q*ao|&iCEOWWxz-VB!0D#_Y4D(PF1xh3KE-9Bc^Gb>SE5m`2 zNmbcduojcj$Q06VBU201=M#7|^q|f?W1>z?0Y;rw$N;sYyYY24t2{+tkM!c$#6uKFt(Ufsx_#CTK%BCYdHdlVH)G zf}`IsnFY=8#5Iwj{BP%p$lT}mO`nqY8$S+=@riO^92g@3#_HU|I50*6jMce^abS!D z7^`y+gRFjnUt#(^;sV64tPj00mNz*wDo7zf5kfU!FFFh*ei0oNMotj`GFe*gdg M07*qoM6N<$f_ysXXaE2J literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-76@2x.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..163f1c7f0f18248df3ebb37210a2b0a0bbf2cad0 GIT binary patch literal 4395 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 Da)UKi literal 0 HcmV?d00001 diff --git a/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-83.5@2x.png b/tests/introspection/iOS/Assets.xcassets/AppIcons.appiconset/icon-app-83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0bac1da399b57d1fd72989a0be346c7cea83a618 GIT binary patch literal 8968 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 + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + MinimumOSVersion + 6.0 + CFBundleName + introspection + CFBundleIdentifier + com.xamarin.introspection + UIDeviceFamily + + 1 + 2 + + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + UILaunchStoryboardName + LaunchScreen + XSAppIconAssets + Assets.xcassets/AppIcons.appiconset + + diff --git a/tests/introspection/iOS/LaunchScreen.storyboard b/tests/introspection/iOS/LaunchScreen.storyboard new file mode 100644 index 000000000000..7981a14b773c --- /dev/null +++ b/tests/introspection/iOS/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/introspection/iOS/Main.cs b/tests/introspection/iOS/Main.cs new file mode 100644 index 000000000000..12c5bdd9b389 --- /dev/null +++ b/tests/introspection/iOS/Main.cs @@ -0,0 +1,24 @@ +#if !__WATCHOS__ +using System; +#if XAMCORE_2_0 +using Foundation; +using UIKit; +#else +using MonoTouch.Foundation; +using MonoTouch.UIKit; +#endif + +namespace dontlink +{ + public class Application + { + // This is the main entry point of the application. + static void Main (string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main (args, null, "AppDelegate"); + } + } +} +#endif // !__WATCHOS__ diff --git a/tests/introspection/iOS/iOSApiClassPtrTest.cs b/tests/introspection/iOS/iOSApiClassPtrTest.cs new file mode 100644 index 000000000000..09f31fafc177 --- /dev/null +++ b/tests/introspection/iOS/iOSApiClassPtrTest.cs @@ -0,0 +1,39 @@ +// +// Test fixture for class_ptr introspection tests +// +// Authors: +// Alex Soto +// +// Copyright 2012-2014 Xamarin Inc. +// +using System; +using System.Reflection; +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif +using NUnit.Framework; + +namespace Introspection { + [TestFixture] + [Preserve (AllMembers = true)] + public class iOSApiClassPtrTest : ApiClassPtrTest { + + protected override bool Skip (Type type) + { + // While the following types are categories and contains a class_ptr + // they are not used at all as extensions since they are just used to expose + // static properties. + switch (type.Name) { + case "NSUrlUtilities_NSCharacterSet": + case "AVAssetTrackTrackAssociation": + return true; + } + return base.Skip (type); + } + } +} + diff --git a/tests/introspection/iOS/iOSApiCtorInitTest.cs b/tests/introspection/iOS/iOSApiCtorInitTest.cs new file mode 100644 index 000000000000..f11dbbc40b93 --- /dev/null +++ b/tests/introspection/iOS/iOSApiCtorInitTest.cs @@ -0,0 +1,315 @@ +// +// Test the generated API `init` selectors are usable by developers +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013 Xamarin Inc. All rights reserved. +// + +using System; +using System.Collections.Generic; +using System.Reflection; +#if XAMCORE_2_0 +#if !__TVOS__ +using PassKit; +#endif +using Foundation; +#if !__WATCHOS__ +using Metal; +#endif +using ObjCRuntime; +using UIKit; +#else +using MonoTouch.PassKit; +using MonoTouch.Foundation; +using MonoTouch.Metal; +using MonoTouch.ObjCRuntime; +using MonoTouch.UIKit; +#endif + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSApiCtorInitTest : ApiCtorInitTest { + + public iOSApiCtorInitTest () + { + Class.ThrowOnInitFailure = false; + ContinueOnFailure = true; + //LogProgress = true; + } + + protected override bool Skip (Type type) + { + switch (type.Namespace) { + // all default ctor did not work and were replaced with [Obsolete("",true)] placeholders + // reflecting on those would create invalid instances (no handle) that crash the app + case "CoreBluetooth": + case "MonoTouch.CoreBluetooth": + return true; + + case "CoreAudioKit": + case "MonoTouch.CoreAudioKit": + case "Metal": + case "MonoTouch.Metal": + // they works with iOS9 beta 4 (but won't work on older simulators) + if ((Runtime.Arch == Arch.SIMULATOR) && !CheckiOSOrTVOSSystemVersion (9,0)) + return true; + break; +#if !__WATCHOS__ + case "MetalKit": + case "MonoTouch.MetalKit": + case "MetalPerformanceShaders": + case "MonoTouch.MetalPerformanceShaders": + if (Runtime.Arch == Arch.SIMULATOR) + return true; + // some devices don't support metal and that crash some API that does not check that, e.g. #33153 + if (!CheckiOSOrTVOSSystemVersion (9,0) || (MTLDevice.SystemDefault == null)) + return true; + break; +#endif // !__WATCHOS__ + } + + switch (type.Name) { + // under iOS7 creating this type will crash later (after test execution) with a stack similar to: + // https://gist.github.com/rolfbjarne/457f78e20c8c31edef5c + case "EKCalendarChooserDelegate": + case "EKEventEditViewController": + return true; + + // Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: There can only be one UIApplication instance. + case "UIApplication": + return true; + // Objective-C exception thrown. Name: NSInvalidArgumentException Reason: UISplitViewController is only supported when running under UIUserInterfaceIdiomPad + case "UISplitViewController": +#if !__WATCHOS__ + // Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: ADInterstitialAd is available on iPad only. + case "ADInterstitialAd": + return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; +#endif + + case "UIVideoEditorController": + return true; + // shows an alert on the simulator + case "MFMessageComposeViewController": + return true; + // shows an alert on the device (if no email address is configured) + case "MFMailComposeViewController": + return true; + +#if !__TVOS__ + // PassKit is not available on iPads + case "PKPassLibrary": + return !PKPassLibrary.IsAvailable; +#endif // !__TVOS__ + + + // default ctor started to throw on iOS7 - we should never have exposed it but, for API compatibility, + // we now have an "empty" obsolete ctor + case "UIFont": + return true; + + case "NSUrlSessionConfiguration": + case "NSUrlSession": + // This crashes when arc frees this object at the end of the scope: + // { NSURLSession *var = [[NSURLSession alloc] init]; } + return true; + + case "GKAchievementViewController": + case "GKLeaderboardViewController": + // technically available since 4.1 - however it got a new base class in 6.0 + // and that new base class GKGameCenterViewController did not exists before 6.0 + // which makes the type unusable in 5.x, ref: https://gist.github.com/spouliot/271b6230a3aa2b58bc6e + return !CheckiOSSystemVersion (6,0); + + // mistake - we should not have exposed those default ctor and now we must live with them + case "GCControllerElement": + case "GCControllerAxisInput": + case "GCControllerButtonInput": + case "GCControllerDirectionPad": + case "GCGamepad": + case "GCExtendedGamepad": + case "GCController": + return true; + + // default constructor are not working on iOS8 so we removed them + // and can't test them even in earlier iOS versions + case "JSManagedValue": + case "MKLocalSearch": + case "MKTileOverlayRenderer": + case "AVAssetResourceLoadingDataRequest": + case "CLBeaconRegion": + case "NSPersistentStoreCoordinator": + return true; + + // Metal is not available on the (iOS8) simulator + case "CAMetalLayer": + return (Runtime.Arch == Arch.SIMULATOR); + +#if !XAMCORE_2_0 + // from iOS8 (beta4) they do not return a valid handle + case "AVAssetResourceLoader": + case "AVAssetResourceLoadingRequest": + case "AVAssetResourceLoadingContentInformationRequest": + return true; + // Started with iOS8 on simulator (always) but it looks like it can happen on devices too + // NSInvalidArgumentException Use initWithAccessibilityContainer: + case "UIAccessibilityElement": + return CheckiOSSystemVersion (8,0); +#endif + // in 8.2 beta 1 this crash the app (simulator) without giving any details in the logs + case "WKUserNotificationInterfaceController": + return true; + + // Both reported in radar #21548819 + // NSUnknownKeyException [ valueForUndefinedKey:]: this class is not key value coding-compliant for the key inputPoint2. + case "CIDepthOfField": + // NSUnknownKeyException [ valueForUndefinedKey:]: this class is not key value coding-compliant for the key inputCropAmount. + case "CISunbeamsGenerator": + return true; + + case "MPMediaItemArtwork": + // NSInvalidArgumentException Reason: image must be non-nil + return true; + default: + return base.Skip (type); + } + } + + static List do_not_dispose = new List (); + + protected override void Dispose (NSObject obj, Type type) + { + switch (type.Name) { + // this crash the application after test completed their execution so we keep it alive + case "AVAudioRecorder": + case "AVCaptureConnection": + case "GKFriendRequestComposeViewController": + case "SKView": + // NSInvalidArgumentException *** -[__NSDictionaryM removeObjectForKey:]: key cannot be nil + case "SKTextureAtlas": + // fails under iOS5 with NSInvalidArgumentException Reason: -[__NSCFDictionary removeObjectForKey:]: attempt to remove nil key + case "NSBundle": + case "NSUrlConnection": // crash too (only on iOS5) + // iOS8 beta 5 -> SIGABRT (only on devices) + case "CABTMidiCentralViewController": + case "CABTMidiLocalPeripheralViewController": + do_not_dispose.Add (obj); + break; + // iOS 9 beta 1 - crash when disposed + case "MidiNetworkConnection": + case "WKNavigation": + case "CIImageAccumulator": + case "NEAppProxyTcpFlow": + case "NEAppProxyUdpFlow": + do_not_dispose.Add (obj); + break; + default: + base.Dispose (obj, type); + break; + } + } + + protected override void CheckHandle (NSObject obj) + { + bool result = obj.Handle != IntPtr.Zero; + if (!result) { + string name = obj.GetType ().Name; + switch (name) { + // FIXME: it's not clear what's the alternative to 'init' and it could be because I have no phone device + case "CTCallCenter": + case "CTTelephonyNetworkInfo": + return; + // to avoid crashes we do not really create (natively) default instances (iOS gives them to us) + // for compatibility purpose - we should never had included the default .ctor in monotouch.dll + case "CAMediaTimingFunction": + case "CLHeading": + case "CLRegion": + case "CLPlacemark": + case "CMAccelerometerData": + case "CMLogItem": + case "CMAttitude": + case "CMDeviceMotion": + case "CMGyroData": + case "CMMagnetometerData": + return; + // under iOS5 only - MPMediaPickerController: Unable to access iPod library. + case "MPMediaPickerController": + return; + // re-enabled as an [Obsolete ("", true)] but it will crash if we create it (which we can since we use reflection) + case "NSTimer": + case "NSCompoundPredicate": + return; + // iOS9 - the instance was "kind of valid" before + case "PKPaymentAuthorizationViewController": + if (CheckiOSSystemVersion (9,0)) + return; + break; + } + base.CheckHandle (obj); + } + } + + protected override void CheckToString (NSObject obj) + { + string name = obj.GetType ().Name; + switch (name) { + // crash at at MonoTouch.Foundation.NSObject.get_Description () [0x0000b] in /mono/ios/monotouch-ios7/monotouch/src/Foundation/NSObject.g.cs:500 + case "SKTexture": + case "MCSession": + // crash at at MonoTouch.Foundation.NSObject.get_Description () [0x0000b] in /Developer/MonoTouch/Source/monotouch/src/Foundation/NSObject.g.cs:554 + case "AVPlayerItemTrack": + case "AVCaptureConnection": + return; + // worked before ios6.0 beta 1 + case "AVComposition": + // new API in iOS7 + case "AVAssetResourceLoadingDataRequest": + // Objective-C exception thrown. Name: NSInvalidArgumentException Reason: Unable to create description in descriptionForLayoutAttribute_layoutItem_coefficient. Something is nil + case "NSLayoutConstraint": + // new in 6.0 + case "AVAssetResourceLoadingRequest": + case "GKScoreChallenge": // Objective-C exception thrown. Name: NSInvalidArgumentException Reason: -[GKScoreChallenge challengeID]: unrecognized selector sent to instance 0x18acc340 + case "GKAchievementChallenge": // Objective-C exception thrown. Name: NSInvalidArgumentException Reason: -[GKAchievementChallenge challengeID]: unrecognized selector sent to instance 0x160f4840 + if (CheckiOSOrTVOSSystemVersion (6,0)) + return; + break; + // crash (when asking `description`) under iOS5 (only) simulator + case "NSUrlConnection": + return; + // iOS 9 beta 1 - crash when called + case "WKFrameInfo": + case "WKNavigation": + case "WKNavigationAction": + if (CheckiOSSystemVersion (9,0)) + return; + break; + default: + base.CheckToString (obj); + break; + } + } + + + protected override void CheckNSObjectProtocol (NSObject obj) + { + switch (obj.GetType ().Name) { + case "NSString": + // according to bots `isKindOf (null)` returns true before iOS 8, ref: #36726 + if (!CheckiOSOrTVOSSystemVersion (8, 0)) + return; + break; + } + base.CheckNSObjectProtocol (obj); + } + + // notes: + // * Splitview controller is expected to have a view controller at index 0 before it's used! + // this happens when we dispose an empty UISplitViewController, harmless + } +} diff --git a/tests/introspection/iOS/iOSApiFieldTest.cs b/tests/introspection/iOS/iOSApiFieldTest.cs new file mode 100644 index 000000000000..cd9eb9183ee8 --- /dev/null +++ b/tests/introspection/iOS/iOSApiFieldTest.cs @@ -0,0 +1,143 @@ +// +// Test the generated API fields (e.g. against typos or OSX-only values) +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013 Xamarin Inc. All rights reserved. +// + +using System; +using System.Reflection; +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +using UIKit; +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +using MonoTouch.UIKit; +#endif +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSApiFieldTest : ApiFieldTest { + + public iOSApiFieldTest () + { + ContinueOnFailure = true; + //LogProgress = true; + } + + protected override bool Skip (Type type) + { + return base.Skip (type); + } + + protected override bool Skip (PropertyInfo p) + { + switch (p.DeclaringType.Namespace) { + case "CoreAudioKit": + case "MonoTouch.CoreAudioKit": + case "Metal": + case "MonoTouch.Metal": + // they works with iOS9 beta 4 (but won't work on older simulators) + if ((Runtime.Arch == Arch.SIMULATOR) && !CheckiOSSystemVersion (9,0)) + return true; + break; + case "MetalKit": + case "MonoTouch.MetalKit": + case "MetalPerformanceShaders": + case "MonoTouch.MetalPerformanceShaders": + if (Runtime.Arch == Arch.SIMULATOR) + return true; + break; + } + + switch (p.Name) { + case "AutoConfigurationHTTPResponseKey": // kCFProxyAutoConfigurationHTTPResponseKey + case "CFNetworkProxiesProxyAutoConfigJavaScript": // kCFNetworkProxiesProxyAutoConfigJavaScript + return true; + + // defined in Apple PDF (online) but not in the HTML documentation + // but also inside CLError.h from iOS 5.1 SDK... + case "ErrorUserInfoAlternateRegionKey": // kCLErrorUserInfoAlternateRegionKey + return true; + + // documented since iOS 4.0 - but the symbols are not in the libraries (see specific unit tests) + case "MakerMinoltaDictionary": // kCGImagePropertyMakerMinoltaDictionary + case "MakerFujiDictionary": // kCGImagePropertyMakerFujiDictionary + case "MakerOlympusDictionary": // kCGImagePropertyMakerOlympusDictionary + case "MakerPentaxDictionary": // kCGImagePropertyMakerPentaxDictionary + return true; + + // ImageIO: documented since iOS 4.3 but null in iOS5 (works on iOS 6.1) + // https://developer.apple.com/library/ios/releasenotes/General/iOS43APIDiffs/ + case "ExifCameraOwnerName": + case "ExifBodySerialNumber": + case "ExifLensSpecification": + case "ExifLensMake": + case "ExifLensModel": + case "ExifLensSerialNumber": + return !CheckiOSOrTVOSSystemVersion (6,1); + + // ImageIO: new in iOS 8 but returns nil (at least in beta 1) seems fixed in iOS9 + case "PNGLoopCount": + case "PNGDelayTime": + case "PNGUnclampedDelayTime": + return !CheckiOSOrTVOSSystemVersion (9,0); + + // CoreServices.CFHTTPMessage - document in 10.9 but returns null + case "_AuthenticationSchemeOAuth1": + return true; + + // Apple does not ship a PushKit for every arch on some devices :( + case "Voip": + return Runtime.Arch == Arch.DEVICE; + + default: + return base.Skip (p); + } + } + + protected override bool Skip (string constantName) + { + switch (constantName) { + // grep ImageIO binary shows those symbols are not part of the binary + // that match older results (nil) when loading them (see above) + case "kCGImagePropertyAPNGLoopCount": + case "kCGImagePropertyAPNGDelayTime": + case "kCGImagePropertyAPNGUnclampedDelayTime": + case "kCGImagePropertyMakerFujiDictionary": + case "kCGImagePropertyMakerMinoltaDictionary": + case "kCGImagePropertyMakerOlympusDictionary": + case "kCGImagePropertyMakerPentaxDictionary": + // + case "kCFHTTPAuthenticationSchemeOAuth1": + return true; + // Apple does not ship a PushKit for every arch on some devices :( + case "PKPushTypeVoIP": + return Runtime.Arch == Arch.DEVICE; + // there's only partial support for metal on the simulator (on iOS9 beta 5) but most other frameworks + // that interop with it are not (yet) supported + case "kCVMetalTextureCacheMaximumTextureAgeKey": + case "MPSRectNoClip": + case "MTKTextureLoaderErrorDomain": + case "MTKTextureLoaderErrorKey": + case "MTKTextureLoaderOptionAllocateMipmaps": + case "MTKTextureLoaderOptionSRGB": + case "MTKTextureLoaderOptionTextureUsage": + case "MTKTextureLoaderOptionTextureCPUCacheMode": + case "MTKModelErrorDomain": + case "MTKModelErrorKey": + return Runtime.Arch == Arch.SIMULATOR; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/tests/introspection/iOS/iOSApiPInvokeTest.cs b/tests/introspection/iOS/iOSApiPInvokeTest.cs new file mode 100644 index 000000000000..724f04cb5fa2 --- /dev/null +++ b/tests/introspection/iOS/iOSApiPInvokeTest.cs @@ -0,0 +1,99 @@ +// +// Test the existing of p/invoked symbols +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2014-2015 Xamarin Inc. All rights reserved. +// + +using System; +using System.Reflection; +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +using UIKit; +#else +using MonoTouch; +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +using MonoTouch.UIKit; +#endif +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSApiPInvokeTest : ApiPInvokeTest { + + protected override bool Skip (string symbolName) + { + bool simulator = Runtime.Arch == Arch.SIMULATOR; + switch (symbolName) { + // Metal support inside simulator is only available in recent iOS9 SDK +#if !__WATCHOS__ + case "MTLCreateSystemDefaultDevice": + return simulator && !UIDevice.CurrentDevice.CheckSystemVersion (9, 0); +#endif + // still most Metal helpers are not available on the simulator (even when the framework is present, it's missing symbols) + case "MPSSupportsMTLDevice": + // neither are the CoreVideo extensions for Metal + case "CVMetalTextureGetTexture": + case "CVMetalTextureIsFlipped": + case "CVMetalTextureGetCleanTexCoords": + case "CVMetalTextureCacheCreate": + case "CVMetalTextureCacheFlush": + case "CVMetalTextureCacheCreateTextureFromImage": + case "MTKMetalVertexDescriptorFromModelIO": + case "MTKModelIOVertexDescriptorFromMetal": + case "MTKModelIOVertexFormatFromMetal": + case "MTKMetalVertexFormatFromModelIO": + return simulator; + + // it's not needed for ARM64 and Apple does not have stubs for them in libobjc.dylib + case "objc_msgSend_stret": + case "objc_msgSendSuper_stret": + return IntPtr.Size == 8 && !simulator; + + default: + return base.Skip (symbolName); + } + } + + protected override bool SkipAssembly (Assembly a) + { + // we only want to check this on a version of iOS that + // 1. is the current SDK target (or a newer one) +#if !__WATCHOS__ + var sdk = new Version (Constants.SdkVersion); + if (!UIDevice.CurrentDevice.CheckSystemVersion (sdk.Major, sdk.Minor)) + return true; +#endif + // 2. on the real target for Xamarin.iOS.dll/monotouch.dll + // as the simulator miss some libraries and symbols + // but the rest of the BCL is fine to test + return (a == typeof (NSObject).Assembly && (Runtime.Arch == Arch.SIMULATOR)); + } + + [Test] + public void NUnitLite () + { + var a = typeof (TestAttribute).Assembly; + if (!SkipAssembly (a)) + Check (a); + } + +#if !__WATCHOS__ + [Test] + public void MonoTouchDialog () + { + // there's no direct reference to MTD - but it's there + var a = AppDelegate.Runner.NavigationController.TopViewController.GetType ().Assembly; + if (!SkipAssembly (a)) + Check (a); + } +#endif + } +} \ No newline at end of file diff --git a/tests/introspection/iOS/iOSApiProtocolTest.cs b/tests/introspection/iOS/iOSApiProtocolTest.cs new file mode 100644 index 000000000000..3b71c8b2f640 --- /dev/null +++ b/tests/introspection/iOS/iOSApiProtocolTest.cs @@ -0,0 +1,286 @@ +// +// Test the generated API for common protocol support +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2013-2015 Xamarin Inc. +// + +using System; +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +using UIKit; +#if !__TVOS__ +using WatchConnectivity; +#endif +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +using MonoTouch.UIKit; +using MonoTouch.WatchConnectivity; +#endif +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSApiProtocolTest : ApiProtocolTest { + + public iOSApiProtocolTest () + { + ContinueOnFailure = true; + // LogProgress = true; + } + + protected override bool Skip (Type type) + { + switch (type.Namespace) { + case "MetalKit": + case "MonoTouch.MetalKit": + case "MetalPerformanceShaders": + case "MonoTouch.MetalPerformanceShaders": + if (Runtime.Arch == Arch.SIMULATOR) + return true; + break; + } + + switch (type.Name) { + // Apple does not ship a PushKit for every arch on some devices :( + case "PKPushCredentials": + case "PKPushPayload": + case "PKPushRegistry": + if (Runtime.Arch != Arch.DEVICE) + return true; + + // Requires iOS 8.2 or later in 32-bit mode + if (!CheckiOSSystemVersion (8, 2) && IntPtr.Size == 4) + return true; + + break; + } + + return base.Skip (type); + } + + protected override bool Skip (Type type, string protocolName) + { + // some code cannot be run on the simulator (e.g. missing frameworks) + switch (type.Namespace) { + case "MonoTouch.Metal": + case "Metal": + case "MonoTouch.CoreAudioKit": + case "CoreAudioKit": + // they works with iOS9 beta 4 (but won't work on older simulators) + if ((Runtime.Arch == Arch.SIMULATOR) && !CheckiOSOrTVOSSystemVersion (9,0)) + return true; + break; + +#if !__TVOS__ + case "WatchConnectivity": + case "MonoTouch.WatchConnectivity": + if (!WCSession.IsSupported) + return true; + break; +#endif // !__TVOS__ + } + + switch (type.Name) { + case "CAMetalLayer": + // that one still does not work with iOS9 beta 4 + if (Runtime.Arch == Arch.SIMULATOR) + return true; + break; +#if !XAMCORE_3_0 + // mistake (base type) fixed by a breaking change + case "MFMailComposeViewControllerDelegate": + if (protocolName == "UINavigationControllerDelegate") + return true; + break; +#endif + // special case: the Delegate property is id so we made A subclass B in managed + // but this test see the conformance is not correct + case "UIImagePickerControllerDelegate": + case "UIVideoEditorControllerDelegate": + if (protocolName == "UINavigationControllerDelegate") + return true; + break; + } + + switch (protocolName) { + case "NSCoding": + switch (type.Name) { + case "GKPlayer": + case "GKLocalPlayer": + // NSSecureCoding is still undocumented, for iOS, and neither is NSCoding for OSX + // and it did not respond before 6.0 (when NSSecureCoding was introduced) + return !CheckiOSOrTVOSSystemVersion (6,0); + case "UITableViewDataSource": + // this is a *protocol( and we do not want to force people to conform to (an + // undocumented "requirement") NSCoding - as ObjC do not have to do this + return true; + // part of HomeKit are *privately* conforming to NSCoding + case "HMCharacteristic": + case "HMCharacteristicMetadata": + case "HMHome": + case "HMService": + case "HMAccessory": + case "HMActionSet": + case "HMCharacteristicWriteAction": + case "HMRoom": + case "HMServiceGroup": + case "HMTimerTrigger": + case "HMTrigger": + case "HMUser": + case "HMZone": + case "HMAccessoryCategory": + case "HMCharacteristicEvent": + case "HMEvent": + case "HMEventTrigger": + case "HMLocationEvent": + // new PassKit for payment also *privately* conforms to NSCoding + case "PKPayment": + case "PKPaymentSummaryItem": + case "PKShippingMethod": + case "PKPaymentRequest": + case "PKPaymentToken": + // iOS9 + case "UIFont": + case "AVAssetTrackSegment": + case "AVComposition": + case "AVMutableComposition": + case "AVCompositionTrackSegment": + case "MKMapSnapshotOptions": + case "WCSessionFile": + case "WCSessionFileTransfer": + return true; + } + break; + case "NSSecureCoding": + switch (type.Name) { + // part of HomeKit are *privately* conforming to NSSecureCoding + case "HMCharacteristic": + case "HMCharacteristicMetadata": + case "HMHome": + case "HMService": + case "HMAccessory": + case "HMActionSet": + case "HMCharacteristicWriteAction": + case "HMRoom": + case "HMServiceGroup": + case "HMTimerTrigger": + case "HMTrigger": + case "HMUser": + case "HMZone": + case "HMAccessoryCategory": + case "HMCharacteristicEvent": + case "HMEvent": + case "HMEventTrigger": + case "HMLocationEvent": + return true; + // new PassKit for payment also *privately* conforms to NSCoding + case "PKPayment": + case "PKPaymentSummaryItem": + case "PKShippingMethod": + case "PKPaymentRequest": + case "PKPaymentToken": + // iOS9 + case "UIFont": + case "AVAssetTrackSegment": + case "AVComposition": + case "AVMutableComposition": + case "AVCompositionTrackSegment": + case "MKMapSnapshotOptions": + case "NSTextTab": + case "WCSessionFile": + case "WCSessionFileTransfer": + return true; + } + break; + case "NSCopying": + switch (type.Name) { + // undocumented conformance (up to 7.0) and conformity varies between iOS versions + case "MKDirectionsRequest": + case "MPMediaItem": + case "MPMediaPlaylist": + case "MPMediaItemCollection": + case "MPMediaEntity": + return true; // skip + // new PassKit for payment also *privately* conforms to NSCoding + case "PKPaymentSummaryItem": + case "PKShippingMethod": + return true; // skip + // iOS9 + case "ACAccount": + case "HKCategorySample": + case "HKCorrelation": + case "HKObject": + case "HKQuantitySample": + case "HKSample": + case "HKWorkout": + return true; + } + break; + case "UIAccessibilityIdentification": + // UIView satisfy the contract - but return false for conformance (and so does all it's subclasses) + return true; + case "UIAppearance": + // we added UIAppearance to some types that do not conform to it + // note: removing them cause the *Appearance types to be removed too + switch (type.Name) { + case "ABPeoplePickerNavigationController": + case "EKEventEditViewController": + case "GKAchievementViewController": + case "GKFriendRequestComposeViewController": + case "GKLeaderboardViewController": + case "GKTurnBasedMatchmakerViewController": + case "MFMailComposeViewController": + case "MFMessageComposeViewController": + return true; + } + break; + case "UITextInputTraits": + // UISearchBar conformance fails before 7.1 - reference bug #33333 + if ((type.Name == "UISearchBar") && !CheckiOSOrTVOSSystemVersion (7,1)) + return true; + break; +#if !XAMCORE_3_0 + case "UINavigationControllerDelegate": + switch (type.Name) { + case "ABPeoplePickerNavigationControllerDelegate": // 37180 + return true; + } + break; +#endif + case "GKSavedGameListener": + switch (type.Name) { + case "GKLocalPlayerListener": // 37180 + return !CheckiOSOrTVOSSystemVersion (8, 0); + } + break; + } + return base.Skip (type, protocolName); + } + + [Test] + public override void SecureCoding () + { + if (!CheckiOSOrTVOSSystemVersion (6,0)) + Assert.Inconclusive ("Requires iOS 6+"); + + base.SecureCoding (); + } + + [Test] + public override void SupportsSecureCoding () + { + if (!CheckiOSOrTVOSSystemVersion (6,0)) + Assert.Inconclusive ("Requires iOS 6+"); + + base.SupportsSecureCoding (); + } + } +} diff --git a/tests/introspection/iOS/iOSApiSelectorTest.cs b/tests/introspection/iOS/iOSApiSelectorTest.cs new file mode 100644 index 000000000000..b7c573642613 --- /dev/null +++ b/tests/introspection/iOS/iOSApiSelectorTest.cs @@ -0,0 +1,608 @@ +// +// Test the generated API selectors against typos or non-existing cases +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2012-2013 Xamarin Inc. All rights reserved. +// + +using System; +using System.Collections.Generic; +using System.Reflection; +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +using UIKit; +#if !__TVOS__ +using WatchConnectivity; +#endif +#else +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +using MonoTouch.UIKit; +using MonoTouch.WatchConnectivity; +#endif +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSApiSelectorTest : CoreSelectorTest { + + public iOSApiSelectorTest () + { + ContinueOnFailure = true; + //LogProgress = true; + } + + protected override bool Skip (Type type) + { + switch (type.Namespace) { + // they don't answer on the simulator (Apple implementation does not work) but fine on devices + case "GameController": + case "MonoTouch.GameController": + return Runtime.Arch == Arch.SIMULATOR; + + case "CoreAudioKit": + case "MonoTouch.CoreAudioKit": + case "Metal": + case "MonoTouch.Metal": + // they works with iOS9 beta 4 (but won't work on older simulators) + if ((Runtime.Arch == Arch.SIMULATOR) && !CheckiOSOrTVOSSystemVersion (9,0)) + return true; + break; + case "MetalKit": + case "MonoTouch.MetalKit": + case "MetalPerformanceShaders": + case "MonoTouch.MetalPerformanceShaders": + if (Runtime.Arch == Arch.SIMULATOR) + return true; + break; + + // Apple does not ship a PushKit for every arch on some devices :( +// case "PushKit": +// case "MonoTouch.PushKit": +// if (Runtime.Arch == Arch.DEVICE) +// return true; +// break; +#if !__TVOS__ + case "WatchConnectivity": + case "MonoTouch.WatchConnectivity": + if (!WCSession.IsSupported) + return true; + break; +#endif // !__TVOS__ + } + + switch (type.Name) { + // abstract superclass + case "UIBarItem": + return true; + + // does not answer to anything ? + case "UILocalNotification": + return true; + + // Metal is not available on the (iOS8) simulator + case "CAMetalLayer": + return (Runtime.Arch == Arch.SIMULATOR); + + default: + return base.Skip (type); + } + } + + protected override bool CheckResponse (bool value, Type actualType, MethodBase method, ref string name) + { + if (value) + return true; + + var declaredType = method.DeclaringType; + + switch (declaredType.Name) { + case "NSUrlSession": + switch (name) { + case "delegateQueue": + case "sessionDescription": + case "setSessionDescription:": + case "delegate": + // does not respond anymore but the properties works (see monotouch-test) + if (CheckiOSOrTVOSSystemVersion (9, 0)) + return true; + break; + } + break; + case "NSUrlSessionTask": + switch (name) { + case "countOfBytesExpectedToReceive": + case "countOfBytesExpectedToSend": + case "countOfBytesReceived": + case "countOfBytesSent": + case "currentRequest": + case "error": + case "originalRequest": + case "response": + case "state": + case "taskDescription": + case "setTaskDescription:": + case "taskIdentifier": + // does not respond anymore but the properties works (see monotouch-test) + if (CheckiOSOrTVOSSystemVersion (9, 0)) + return true; + break; + } + break; + case "NSUrlSessionConfiguration": + case "NSUrlSessionStreamTask": + // does not respond anymore but the properties works (see monotouch-test for a partial list) + if (CheckiOSOrTVOSSystemVersion (9, 0)) + return true; + break; + + case "AVAssetDownloadTask": + switch (name) { + case "currentRequest": + case "originalRequest": + case "response": + if (CheckiOSOrTVOSSystemVersion (9, 0)) + return true; + break; + } + break; + case "CMSensorRecorder": + switch (name) { + // breaking change from Apple in iOS 9.3 betas + // https://trello.com/c/kqlEkPbG/30-24508290-cmsensorrecorder-breaking-change-re-opening-24231250 + // https://trello.com/c/pKLOLjVJ/29-24231250-coremotion-api-removal-without-deprecation + case "accelerometerDataFromDate:toDate:": + case "recordAccelerometerForDuration:": + if (!CheckiOSOrTVOSSystemVersion (9, 3)) + return true; + break; + } + break; + } + + switch (name) { + // UIResponderStandardEditActions - stuffed inside UIResponder + case "cut:": + case "copy:": + case "paste:": + case "delete:": + case "select:": + case "selectAll:": + // A subclass of UIResponder typically implements this method... + case "toggleBoldface:": + case "toggleItalics:": + case "toggleUnderline:": + if (declaredType.Name == "UIResponder") + return true; + break; + case "makeTextWritingDirectionLeftToRight:": + case "makeTextWritingDirectionRightToLeft:": + // MonoTouch.AddressBookUI.ABNewPersonViewController + // MonoTouch.AddressBookUI.ABPeoplePickerNavigationController + // MonoTouch.AddressBookUI.ABPersonViewController + if (declaredType.Name == "UIResponder") + return true; + break; +#if !XAMCORE_2_0 + case "enableInputClicksWhenVisible": + // defined in UIInputViewAudioFeedback protocol + // meant to be added (not part of iOS) in custom UIView and defined (by default) by MonoTouch + if (declaredType.Name == "UIView") + return true; + break; + case "subtitle": + // exists because of MKAnnotation protocol + if (declaredType.Name == "MKPlacemark") + return true; + break; + case "setCoordinate:": + // exists because of MKAnnotation protocol + if (declaredType.Name == "MKShape" || declaredType.Name == "MKPlacemark") + return true; + break; + case "intersectsMapRect:": + // optional method of a protocol MKTileOverlay implements. + if (declaredType.Name == "MKTileOverlay") + return true; + break; +#endif + case "autocapitalizationType": + case "setAutocapitalizationType:": + case "autocorrectionType": + case "setAutocorrectionType:": + case "keyboardType": + case "setKeyboardType:": + case "spellCheckingType": + case "setSpellCheckingType:": + // UITextInputTraits and UITextInputProtocol + if (declaredType.Name == "UITextField" || declaredType.Name == "UITextView") + return true; + if (CheckiOSOrTVOSSystemVersion (7,1) && declaredType.Name == "UISearchBar") + return true; + break; + case "keyboardAppearance": + case "setKeyboardAppearance:": + case "returnKeyType": + case "setReturnKeyType:": + case "enablesReturnKeyAutomatically": + case "setEnablesReturnKeyAutomatically:": + case "isSecureTextEntry": + case "setSecureTextEntry:": + // UITextInputTraits and UITextInput Protocol + switch (declaredType.Name) { + case "UITextField": + case "UITextView": + case "UISearchBar": + return true; + } + break; + case "textStylingAtPosition:inDirection:": + case "positionWithinRange:atCharacterOffset:": + case "characterOffsetOfPosition:withinRange:": + case "shouldChangeTextInRange:replacementText:": + // UITextInputTraits and UITextInputProtocol + if (declaredType.Name == "UITextField" || declaredType.Name == "UITextView") + return true; + // ignore UISearchBar before iOS8 - it did not really implement UITextInput + if (declaredType.Name == "UISearchBar" && !CheckiOSSystemVersion (8,0)) + return true; + break; + case "dictationRecognitionFailed": + case "dictationRecordingDidEnd": + case "insertDictationResult:": + // iOS 5.1 and not every device (or simulator) + if (declaredType.Name == "UITextField" || declaredType.Name == "UITextView") + return true; + break; + // special case: see http://developer.apple.com/library/ios/#documentation/GLkit/Reference/GLKViewController_ClassRef/Reference/Reference.html + case "update": + if (declaredType.Name == "GLKViewController") + return true; + break; + case "thumbnailImageAtTime:timeOption:": + case "requestThumbnailImagesAtTimes:timeOption:": + case "cancelAllThumbnailImageRequests": + case "accessLog": + case "errorLog": + case "timedMetadata": + if (declaredType.Name == "MPMoviePlayerController") + return true; + break; + // deprecated (removed in iOS 3.2) + case "backgroundColor": + case "setBackgroundColor:": + case "movieControlMode": + case "setMovieControlMode:": + if (declaredType.Name == "MPMoviePlayerController") + return true; + break; + case "skipToNextItem": + case "skipToBeginning": + case "skipToPreviousItem": + case "setNowPlayingItem:": + if (actualType.Name == "MPMusicPlayerController") + return true; + break; + // deprecated (according to docs) but actually removed (test) in iOS 6 + case "useApplicationAudioSession": + case "setUseApplicationAudioSession:": + if (declaredType.Name == "MPMoviePlayerController") + return CheckiOSSystemVersion (6,0); + break; + + // iOS6 - headers says readwrite but they do not respond + case "setUUID:": + case "setIsPrimary:": + if (declaredType.Name == "CBMutableService") + return CheckiOSSystemVersion (6, 0); + if (declaredType.Name == "CBMutableCharacteristic") + return CheckiOSSystemVersion (9, 0); + break; + + // documented since 4.0 - but does not answer on an iPad1 with 5.1.1 + case "isAdjustingFocus": + if (declaredType.Name == "AVCaptureDevice") + return true; + break; + + // GameKit: documented since 4.1 - but does not answer + case "alias": + if (declaredType.Name == "GKPlayer") + return true; + break; + case "playerID": + switch (declaredType.Name) { + case "GKPlayer": + case "GKScore": + case "GKTurnBasedParticipant": // iOS 5 + return true; + } + break; + case "category": + case "setCategory:": + case "date": + case "formattedValue": + case "rank": + case "value": + case "setValue:": + case "context": // iOS5 + case "setContext:": // iOS5 + if (declaredType.Name == "GKScore") + return true; + break; + case "isUnderage": + if (declaredType.Name == "GKLocalPlayer") + return true; + break; + case "identifier": + if (declaredType.Name == "GKAchievement" || declaredType.Name == "GKAchievementDescription") + return true; + break; + case "setIdentifier:": + case "percentComplete": + case "setPercentComplete:": + case "lastReportedDate": + case "setLastReportedDate:": + if (declaredType.Name == "GKAchievement") + return true; + break; + case "achievedDescription": + case "isHidden": + case "maximumPoints": + case "title": + case "unachievedDescription": + if (declaredType.Name == "GKAchievementDescription") + return true; + break; + // 5.0 + case "lastTurnDate": + case "matchOutcome": + case "setMatchOutcome:": + if (declaredType.Name == "GKTurnBasedParticipant") + return true; + break; + case "creationDate": + case "matchData": + case "message": + case "setMessage:": + if (declaredType.Name == "GKTurnBasedMatch") + return true; + break; + + // iOS6 - protocols for UICollectionView + case "numberOfSectionsInCollectionView:": + case "collectionView:viewForSupplementaryElementOfKind:atIndexPath:": + case "collectionView:shouldHighlightItemAtIndexPath:": + case "collectionView:didHighlightItemAtIndexPath:": + case "collectionView:didUnhighlightItemAtIndexPath:": + case "collectionView:shouldSelectItemAtIndexPath:": + case "collectionView:shouldDeselectItemAtIndexPath:": + case "collectionView:didSelectItemAtIndexPath:": + case "collectionView:didDeselectItemAtIndexPath:": + case "collectionView:didEndDisplayingCell:forItemAtIndexPath:": + case "collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath:": + case "collectionView:shouldShowMenuForItemAtIndexPath:": + case "collectionView:canPerformAction:forItemAtIndexPath:withSender:": + case "collectionView:performAction:forItemAtIndexPath:withSender:": + // which also inherits from UIScrollViewDelegate + case "scrollViewDidScroll:": + case "scrollViewWillBeginDragging:": + case "scrollViewDidEndDragging:willDecelerate:": + case "scrollViewWillBeginDecelerating:": + case "scrollViewDidEndDecelerating:": + case "scrollViewDidEndScrollingAnimation:": + case "viewForZoomingInScrollView:": + case "scrollViewShouldScrollToTop:": + case "scrollViewDidScrollToTop:": + case "scrollViewDidEndZooming:withView:atScale:": + case "scrollViewDidZoom:": + case "scrollViewWillBeginZooming:withView:": + case "scrollViewWillEndDragging:withVelocity:targetContentOffset:": + if (declaredType.Name == "UICollectionViewController") + return CheckiOSOrTVOSSystemVersion (6,0); + break; + + // failing (check why) + case "initialLayoutAttributesForInsertedItemAtIndexPath:": + case "initialLayoutAttributesForInsertedSupplementaryElementOfKind:atIndexPath:": + case "finalLayoutAttributesForDeletedItemAtIndexPath:": + case "finalLayoutAttributesForDeletedSupplementaryElementOfKind:atIndexPath:": + if (declaredType.Name == "UICollectionViewLayout") + return CheckiOSSystemVersion (6,0); + break; + + // This is implemented by internal concrete classes of NSFileHandle + case "readInBackgroundAndNotify": + case "readInBackgroundAndNotifyForModes:": + case "readToEndOfFileInBackgroundAndNotifyForModes:": + case "readToEndOfFileInBackgroundAndNotify": + case "acceptConnectionInBackgroundAndNotifyForModes:": + case "acceptConnectionInBackgroundAndNotify": + case "waitForDataInBackgroundAndNotifyForModes:": + case "waitForDataInBackgroundAndNotify": + if (declaredType.Name == "NSFileHandle") + return true; + break; + + // UITableViewController conforms to both UITableViewDelegate and UITableViewDataSource + case "tableView:canEditRowAtIndexPath:": + case "tableView:canMoveRowAtIndexPath:": + case "sectionIndexTitlesForTableView:": + case "tableView:sectionForSectionIndexTitle:atIndex:": + case "tableView:commitEditingStyle:forRowAtIndexPath:": + case "tableView:moveRowAtIndexPath:toIndexPath:": + case "tableView:willDisplayCell:forRowAtIndexPath:": + case "tableView:accessoryTypeForRowWithIndexPath:": + case "tableView:accessoryButtonTappedForRowWithIndexPath:": + case "tableView:willSelectRowAtIndexPath:": + case "tableView:willDeselectRowAtIndexPath:": + case "tableView:didSelectRowAtIndexPath:": + case "tableView:didDeselectRowAtIndexPath:": + case "tableView:editingStyleForRowAtIndexPath:": + case "tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:": + case "tableView:shouldIndentWhileEditingRowAtIndexPath:": + case "tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:": + case "tableView:shouldShowMenuForRowAtIndexPath:": + case "tableView:canPerformAction:forRowAtIndexPath:withSender:": + case "tableView:performAction:forRowAtIndexPath:withSender:": + case "tableView:willDisplayHeaderView:forSection:": + case "tableView:willDisplayFooterView:forSection:": + case "tableView:didEndDisplayingCell:forRowAtIndexPath:": + case "tableView:didEndDisplayingHeaderView:forSection:": + case "tableView:didEndDisplayingFooterView:forSection:": + case "tableView:shouldHighlightRowAtIndexPath:": + case "tableView:didHighlightRowAtIndexPath:": + case "tableView:didUnhighlightRowAtIndexPath:": + // iOS7 + case "tableView:estimatedHeightForRowAtIndexPath:": + case "tableView:estimatedHeightForHeaderInSection:": + case "tableView:estimatedHeightForFooterInSection:": + // iOS 8 + case "tableView:editActionsForRowAtIndexPath:": + if (declaredType.Name == "UITableViewController") + return true; + break; + + // iOS7 beta issue ? remains in beta 5 / sim + // MCSession documents the cancelConnectPeer: selector but it does not answer + case "cancelConnectPeer:": + // CBCharacteristic documents the selector but does not respond + case "subscribedCentrals": + // UIPrintFormatter header attributedText says the API is not approved yet - and it does not respond + case "attributedText": + case "setAttributedText:": + // UISplitViewController + case "splitViewControllerSupportedInterfaceOrientations:": + case "splitViewControllerPreferredInterfaceOrientationForPresentation:": + return true; + + case "color": + case "setColor:": + case "font": + case "setFont:": + case "text": + case "setText:": + case "textAlignment": + case "setTextAlignment:": + // iOS7 GM a "no text" instance does not answer to the selector (but you can call them) + if (declaredType.Name == "UISimpleTextPrintFormatter") + return true; + break; + + case "copyWithZone:": + switch (declaredType.Name) { + // not conforming to NSCopying in 5.1 SDK + case "UIFont": + return !CheckiOSSystemVersion (6,0); + // not conforming to NSCopying before 7.0 SDK + case "CBPeripheral": + return !CheckiOSSystemVersion (7,0); + // not conforming to NSCopying before 8.0 SDK + case "AVMetadataFaceObject": + return !CheckiOSSystemVersion (8,0); + // not conforming to NSCopying before 8.2 SDK + case "HKUnit": + return !CheckiOSSystemVersion (8,2); + case "HKBiologicalSexObject": + case "HKBloodTypeObject": + return !CheckiOSSystemVersion (9,0); + } + break; + + // on iOS8.0 this does not work on the simulator (but works on devices) + case "language": + if (declaredType.Name == "AVSpeechSynthesisVoice" && CheckiOSSystemVersion (8,0) && Runtime.Arch == Arch.SIMULATOR) + return true; + break; + + // new, optional members of UIDynamicItem protocol in iOS9 + case "collisionBoundingPath": + case "collisionBoundsType": + switch (declaredType.Name) { + case "UICollectionViewLayoutAttributes": + case "UIView": + case "UIDynamicItemGroup": + return true; + } + break; + + // SceneKit integration with Metal is not working on simulators (at least for iOS9 beta 5) + case "currentRenderCommandEncoder": + case "colorPixelFormat": + case "commandQueue": + case "depthPixelFormat": + case "device": + case "stencilPixelFormat": + switch (declaredType.Name) { + case "SCNRenderer": + case "SCNView": + return Runtime.Arch == Arch.SIMULATOR; + } + break; + +#if XAMCORE_2_0 + // some types adopted NS[Secure]Coding after the type was added + // and for unified that's something we generate automatically (so we can't put [iOS] on them) + case "encodeWithCoder:": + switch (declaredType.Name) { + // UITextInputMode was added in 4.2 but conformed to NSSecureCoding only from 7.0+ + case "UITextInputMode": + return !CheckiOSSystemVersion (7,0); + // iOS9 + case "HKBiologicalSexObject": + case "HKBloodTypeObject": + return !CheckiOSSystemVersion (9,0); + } + break; +#else + // that was a binding mistake - the API should not have been exposed (not in the header file) + // we'll ignore them for compat - but won't provide them in the new assemblies + case "backgroundImageForBarMetrics:": + case "setBackgroundImage:forBarMetrics:": + if (declaredType.Name == "UISearchBar" && CheckiOSSystemVersion (8,0)) + return true; + break; +#endif + } + + return base.CheckResponse (value, actualType, method, ref name); + } + + protected override bool CheckStaticResponse (bool value, Type actualType, Type declaredType, ref string name) + { + switch (name) { + // new API in iOS9 beta 5 but is does not respond when queried - https://bugzilla.xamarin.com/show_bug.cgi?id=33431 + case "geometrySourceWithBuffer:vertexFormat:semantic:vertexCount:dataOffset:dataStride:": + switch (declaredType.Name) { + case "SCNGeometrySource": + return true; + } + break; + } + return base.CheckStaticResponse (value, actualType, declaredType, ref name); + } + + static List do_not_dispose = new List (); + + protected override void Dispose (NSObject obj, Type type) + { + switch (type.Name) { + // this crash the application after test completed their execution so we keep them alive + case "GKFriendRequestComposeViewController": + case "PKAddPassesViewController": + case "SKView": + do_not_dispose.Add (obj); + break; + default: + base.Dispose (obj, type); + break; + } + } + } +} \ No newline at end of file diff --git a/tests/introspection/iOS/iOSApiSignatureTest.cs b/tests/introspection/iOS/iOSApiSignatureTest.cs new file mode 100644 index 000000000000..d552c8baabf0 --- /dev/null +++ b/tests/introspection/iOS/iOSApiSignatureTest.cs @@ -0,0 +1,180 @@ +// +// iOS tests for the generated API selectors against typos or non-existing cases +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2013 Xamarin Inc. All rights reserved. +// + +using System; +using System.Reflection; + +using NUnit.Framework; + +#if XAMCORE_2_0 +using ObjCRuntime; +using Foundation; +using UIKit; +#else +using MonoTouch.ObjCRuntime; +using MonoTouch.Foundation; +using MonoTouch.UIKit; +#endif + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSApiSignatureTest : ApiSignatureTest { + + public iOSApiSignatureTest () + { + ContinueOnFailure = true; + //LogProgress = true; + } + + protected override int Size (Type t, bool simd = false) + { + switch (t.Name) { + // rdar 21375616 - Breaking change with EventKit[UI] enum base type + // EventKit.EK* enums are anonymous enums in 10.10 and iOS 8, but an NSInteger in 10.11 and iOS 9. + case "EKCalendarChooserSelectionStyle": + case "EKCalendarChooserDisplayStyle": + if (!IsOSX11OrIOS9) + return 4; + break; + } + return base.Size (t, simd); + } + + protected override bool Skip (Type type, MethodBase method, string selector) + { + switch (type.Name) { + case "UIAlertView": + // variable length parameters ... + if (selector == "initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:") + return true; + break; + case "UIViewController": + switch (selector) { + // offically added in 6.0 - but retroactively supported in iOS5 (including documentation) + // the code works (see monotouch-test.app) but Apple changed their return value in 6.0 + // (they used to return `bool`) + case "beginAppearanceTransition:animated:": + case "endAppearanceTransition": + if (!CheckiOSOrTVOSSystemVersion (6,0)) + return true; + break; + } + break; + case "NKIssue": + // Apple "promoted" this to `NSInteger` in iOS8 but this already existed (as a 32bits value) in iOS 7.x + // sadly, and even with a bug report with a few exchanges, this was not fixed before iOS8 GM :-( + // 64bits application for iOS 7.x will be uncommon so we prefer to be forward compatible + if (selector == "status") + return !CheckiOSSystemVersion (8,0); + break; + case "CMMotionManager": + // iOS 8.3 changed CMMotionManager from 4 to 8 bytes on 64bits CPU and we have to follow that breaking + // change unless Apple revert that before final. [radar 20295259] + if ((IntPtr.Size == 4) || CheckiOSSystemVersion (8,3)) + return false; + // which means iOS 8.2 (and earlier can't match) + switch (selector) { + case "startDeviceMotionUpdatesUsingReferenceFrame:": + case "startDeviceMotionUpdatesUsingReferenceFrame:toQueue:withHandler:": + case "attitudeReferenceFrame": + return true; + default: + return false; + } + } + + return base.Skip (type, method, selector); + } + + protected override bool IsValidStruct (Type type, string structName) + { + switch (structName) { + // CIImage 'static MonoTouch.CoreImage.CIImage FromImageBuffer(MonoTouch.CoreVideo.CVPixelBuffer)' selector: imageWithCVPixelBuffer: == @12@0:4^{__CVBuffer=} + case "__CVBuffer": + return type.Name == "CVPixelBuffer" || type.Name == "CVImageBuffer"; + } + return base.IsValidStruct (type, structName); + } + + // only handle exception here (to return true) otherwise call base to deal with it + // `caller` is provided to make it easier to detect "special" cases + protected override bool Check (char encodedType, Type type) + { + // return an error if null (instead of throwing) so we can continue execution + if (type == null) + return false; + + switch (encodedType) { + case 'c': // char, used for C# bool +#if !XAMCORE_2_0 + switch (type.FullName) { + // looks like it returns a bool even if documented as a void + // UIPrintInteractionController 'instance Void Present(Boolean, MonoTouch.UIKit.UIPrintInteractionCompletionHandler)' selector: presentAnimated:completionHandler: + // update: documentation (and header) mistake that Apple corrected (IIRC I filled that issue) + case "System.Void": + return CurrentType.Name == "UIPrintInteractionController"; + } +#endif + break; + // float (32 bits) + case 'f': + switch (type.FullName) { + // documented (web and header file) as NSInteger + // UIImageView 'instance Void set_AnimationRepeatCount(Int32)' selector: setAnimationRepeatCount: == v12@0:4f8 + case "System.Int32": + return CurrentType.FullName == "MonoTouch.UIKit.UIImageView"; + } + break; + case 'i': + switch (type.FullName) { + case "MonoTouch.EventKitUI.EKCalendarChooserSelectionStyle": + case "MonoTouch.EventKitUI.EKCalendarChooserDisplayStyle": + case "EventKitUI.EKCalendarChooserSelectionStyle": + case "EventKitUI.EKCalendarChooserDisplayStyle": + return (IntPtr.Size == 4) || !IsOSX11OrIOS9; + case "System.UInt32": + // numberOfTouchesRequired was signed before iOS6, unsigned since then + return true; + } + break; + // unsigned 32 bits + case 'I': + switch (type.FullName) { + case "System.Int32": + // sign-ness mis-binding, several of them (not critical) + // CBATTRequest 'instance Int32 get_Offset()' selector: offset == I8@0:4 + return true; + } + break; + // unsigned 32 bits + case 'L': + switch (type.FullName) { + // sign-ness mis-binding (not critical) e.g. + // CAMediaTimingFunction 'instance Void GetControlPointAtIndex(Int32, IntPtr)' selector: getControlPointAtIndex:values: == v16@0:4L8[2f]12 + case "System.Int32": + return true; + } + break; + // unsigned 64 bits + case 'Q': + switch (type.FullName) { + // sign-ness mis-binding (not critical) e.g. + // NSIncrementalStoreNode 'instance Int64 get_Version()' selector: version == Q8@0:4 + case "System.Int64": + return true; + } + break; + } + return base.Check (encodedType, type); + } + } +} \ No newline at end of file diff --git a/tests/introspection/iOS/iOSApiTypoTest.cs b/tests/introspection/iOS/iOSApiTypoTest.cs new file mode 100644 index 000000000000..c4377e53e4e8 --- /dev/null +++ b/tests/introspection/iOS/iOSApiTypoTest.cs @@ -0,0 +1,55 @@ +using System; +using NUnit.Framework; + +#if XAMCORE_2_0 +using Foundation; +using ObjCRuntime; +using UIKit; +#else +using MonoTouch; +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +using MonoTouch.UIKit; +#endif + +namespace Introspection { + + [TestFixture] + public class iOSApiTypoTest : ApiTypoTest { +#if !__WATCHOS__ + UITextChecker checker = new UITextChecker (); +#endif + + [SetUp] + public void SetUp () + { +#if __WATCHOS__ + Assert.Fail ("Need to find alternative for UITextChecker on WatchOS."); +#else + // that's slow and there's no value to run it on devices as the API names + // being verified won't change from the simulator + if (Runtime.Arch == Arch.DEVICE) + Assert.Ignore ("Typos only detected on simulator"); + + // the dictionary used by iOS varies with versions and + // we don't want to maintain special cases for each version + var sdk = new Version (Constants.SdkVersion); + if (!UIDevice.CurrentDevice.CheckSystemVersion (sdk.Major, sdk.Minor)) + Assert.Ignore ("Typos only verified using the latest SDK"); +#endif + } + + public override string GetTypo (string txt) + { +#if __WATCHOS__ + return string.Empty; +#else + var checkRange = new NSRange (0, txt.Length); + var typoRange = checker.RangeOfMisspelledWordInString (txt, checkRange, checkRange.Location, false, "en_US"); + if (typoRange.Length == 0) + return String.Empty; + return txt.Substring ((int) typoRange.Location, (int) typoRange.Length); +#endif + } + } +} diff --git a/tests/introspection/iOS/iOSApiWeakPropertyTest.cs b/tests/introspection/iOS/iOSApiWeakPropertyTest.cs new file mode 100644 index 000000000000..2c2f3c84b84c --- /dev/null +++ b/tests/introspection/iOS/iOSApiWeakPropertyTest.cs @@ -0,0 +1,54 @@ +using System; +using System.Reflection; + +#if XAMCORE_2_0 +using Foundation; +#else +using MonoTouch.Foundation; +#endif + +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSApiWeakPropertyTest : ApiWeakPropertyTest { + + public iOSApiWeakPropertyTest () + { + ContinueOnFailure = true; + } + + protected override bool Skip (PropertyInfo property) + { + switch (property.DeclaringType.Name) { + // WeakVideoGravity is an NSString that we could/should provide a better binding (e.g. enum) + case "AVPlayerViewController": + return property.Name == "WeakVideoGravity"; + // CATextLayer.WeakFont is done correctly by hand + case "CATextLayer": + return property.Name == "WeakFont"; + // NSAttributedStringDocumentAttributes is a DictionaryContainer that expose some Weak* NSDictionary + case "NSAttributedStringDocumentAttributes": + return property.Name == "WeakDocumentType" || property.Name == "WeakDefaultAttributes"; + // UIFontAttributes is a DictionaryContainer that expose a Weak* NSDictionary + case "UIFontAttributes": + return property.Name == "WeakFeatureSettings"; + // UIStringAttributes is a DictionaryContainer that expose a Weak* NSString + case "UIStringAttributes": + return property.Name == "WeakTextEffect"; +#if !XAMCORE_3_0 + // #37451 - setter does not exists but we have to keep it for binary compatibility + // OTOH we can't give it a selector (private API) even if we suspect Apple is mostly running `strings` on executable + case "IUIViewControllerPreviewing": + return property.Name == "WeakDelegate"; + case "UIViewControllerPreviewingWrapper": + return property.Name == "WeakDelegate"; +#endif + } + return base.Skip (property); + } + } +} \ No newline at end of file diff --git a/tests/introspection/iOS/iOSCoreImageFiltersTest.cs b/tests/introspection/iOS/iOSCoreImageFiltersTest.cs new file mode 100644 index 000000000000..dcaffc5ebf6a --- /dev/null +++ b/tests/introspection/iOS/iOSCoreImageFiltersTest.cs @@ -0,0 +1,36 @@ +// +// Test the generated API for all iOS CoreImage filters +// +// Authors: +// Sebastien Pouliot +// Alex Soto +// +// Copyright 2012-2013 Xamarin Inc. All rights reserved. +// + +#if !__WATCHOS__ + +using System; +using System.Reflection; +#if XAMCORE_2_0 +using CoreImage; +using Foundation; +using ObjCRuntime; +#else +using MonoTouch.CoreImage; +using MonoTouch.Foundation; +using MonoTouch.ObjCRuntime; +#endif +using NUnit.Framework; + +namespace Introspection { + + [TestFixture] + // we want the tests to be available because we use the linker + [Preserve (AllMembers = true)] + public class iOSCoreImageFiltersTest : ApiCoreImageFiltersTest { + + + } +} +#endif // !__WATCHOS__ diff --git a/tests/introspection/iOS/introspection-ios.csproj b/tests/introspection/iOS/introspection-ios.csproj new file mode 100644 index 000000000000..974d78ac4224 --- /dev/null +++ b/tests/introspection/iOS/introspection-ios.csproj @@ -0,0 +1,187 @@ + + + + Debug + iPhoneSimulator + 8.0.30703 + 2.0 + {208744BD-504E-47D7-9A98-1CF02454A6DA} + {6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + Introspection + introspection + MonoTouch + + + True + full + False + bin\iPhoneSimulator\Debug + DEBUG;MONOTOUCH + prompt + 4 + False + None + True + -v -v + + + i386 + iPhone Developer + + + none + False + bin\iPhoneSimulator\Release + prompt + 4 + False + None + -v -v -gcc_flags="-weak_framework GameController" + i386 + + + MONOTOUCH + + + True + full + False + bin\iPhone\Debug + DEBUG;MONOTOUCH + prompt + 4 + False + True + iPhone Developer + None + + + -v -v --registrar:static + ARMv7 + + + none + False + bin\iPhone\Release + prompt + 4 + False + iPhone Developer + -v -v + True + + + None + ARMv7 + MONOTOUCH + + + true + full + false + bin\iPhone\Debug + DEBUG;MONOTOUCH + prompt + 4 + false + ARMv7 + + + None + true + iPhone Developer + -v -v --registrar:static + + + + + + + + + + + + + + + + + + + + + ApiBaseTest.cs + + + ApiClassPtrTest.cs + + + ApiCMAttachmentTest.cs + + + ApiCoreImageFiltersTest.cs + + + ApiCtorInitTest.cs + + + ApiFieldTest.cs + + + ApiPInvokeTest.cs + + + ApiProtocolTest.cs + + + ApiSelectorTest.cs + + + ApiSignatureTest.cs + + + ApiStructTest.cs + + + ApiTypoTest.cs + + + ApiWeakPropertyTest.cs + + + CoreSelectorTest.cs + + + EnvironmentVariable.cs + + + PlatformInfo.cs + + + + + + + + + + + + + + + + + + + + + + + xamarin1.png + + + + diff --git a/tests/introspection/xamarin1.png b/tests/introspection/xamarin1.png new file mode 100644 index 0000000000000000000000000000000000000000..9874955dd0988c5aee845e53af76394a28fdc5ff GIT binary patch literal 20775 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