diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index 79be2a9ecb1d..e111f1daff11 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -94,7 +94,7 @@
-
+
@@ -554,7 +554,7 @@
-
+
-
+
@@ -624,6 +633,10 @@
<_IsManagedStaticRegistrarFeature Condition="'$(Registrar)' == 'managed-static'">true
<_IsManagedStaticRegistrarFeature Condition="'$(Registrar)' != 'managed-static'">false
+
+ <_IsTrimmableStaticRegistrarFeature Condition="'$(Registrar)' == 'trimmable-static'">true
+ <_IsTrimmableStaticRegistrarFeature Condition="'$(Registrar)' != 'trimmable-static'">false
+
<_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' == 'NativeAOT'">true
<_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' != 'NativeAOT'">false
@@ -685,6 +698,8 @@
SkipMarkingNSObjectsInUserAssemblies=$(_SkipMarkingNSObjectsInUserAssemblies)
TargetArchitectures=$(TargetArchitectures)
TargetFramework=$(_ComputedTargetFrameworkMoniker)
+ TypeMapAssemblyName=$(_TypeMapAssemblyName)
+ TypeMapOutputDirectory=$(_TypeMapOutputDirectory)
UseLlvm=$(MtouchUseLlvm)
Verbosity=$(_BundlerVerbosity)
Warn=$(_BundlerWarn)
@@ -767,6 +782,7 @@
+
@@ -801,7 +817,8 @@
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(Registrar)' == 'managed-static'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(Registrar)' == 'managed-static' Or '$(Registrar)' == 'trimmable-static'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.TrimmableRegistrarStep" Condition="'$(Registrar)' == 'trimmable-static'" />
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/SymbolStrip.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/SymbolStrip.cs
index 5fe7b56b7fb3..759d98fb8121 100644
--- a/msbuild/Xamarin.MacDev.Tasks/Tasks/SymbolStrip.cs
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/SymbolStrip.cs
@@ -27,10 +27,16 @@ public class SymbolStrip : XamarinParallelTask, ITaskCallback {
public string Kind { get; set; } = string.Empty;
#endregion
- bool GetIsFramework (ITaskItem item)
+ bool GetIsFrameworkOrDynamicLibrary (ITaskItem item)
{
var value = GetNonEmptyStringOrFallback (item, "Kind", Kind);
- return string.Equals (value, "Framework", StringComparison.OrdinalIgnoreCase);
+ if (string.Equals (value, "Framework", StringComparison.OrdinalIgnoreCase))
+ return true;
+
+ if (string.Equals (value, "Dynamic", StringComparison.OrdinalIgnoreCase) || item.ItemSpec.EndsWith (".dylib", StringComparison.OrdinalIgnoreCase))
+ return true;
+
+ return false;
}
void ExecuteStrip (ITaskItem item)
@@ -45,7 +51,7 @@ void ExecuteStrip (ITaskItem item)
args.Add (symbolFile);
}
- if (GetIsFramework (item)) {
+ if (GetIsFrameworkOrDynamicLibrary (item)) {
// Only remove debug symbols from frameworks.
args.Add ("-S");
args.Add ("-x");
diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.props b/msbuild/Xamarin.Shared/Xamarin.Shared.props
index 4b2c9b8173b7..01c764d59679 100644
--- a/msbuild/Xamarin.Shared/Xamarin.Shared.props
+++ b/msbuild/Xamarin.Shared/Xamarin.Shared.props
@@ -224,6 +224,10 @@ Copyright (C) 2020 Microsoft. All rights reserved.
<_NativeExecutableName Condition="'$(_NativeExecutableName)' == ''">$(AssemblyName)
+
+
+ <_TypeMapAssemblyName Condition="'$(_TypeMapAssemblyName)' == ''">_Microsoft.$(_PlatformName).TypeMaps
+ <_TypeMapOutputDirectory Condition="'$(_TypeMapOutputDirectory)' == ''">$(DeviceSpecificIntermediateOutputPath)typemap\
diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
index 8a12ca7f29b0..7718f0fbf1d8 100644
--- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets
+++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
@@ -467,9 +467,16 @@ Copyright (C) 2018 Microsoft. All rights reserved.
-
-
-
+
+
+ <_BundleResourceToSave Include="@(BundleResource)" Condition="'%(BundleResource.PublishFolderType)' == ''" />
+ <_ContentToSave Include="@(Content)" Condition="'%(Content.PublishFolderType)' == ''" />
+
+
+
@@ -2963,6 +2970,15 @@ Copyright (C) 2018 Microsoft. All rights reserved.
%(Filename).dSYM
+
+ <_MergedAppBundleDylib Include="$(AppBundleDir)/$(_AppContentsRelativePathForPostProcessing)*.dylib" Condition="'$(RuntimeIdentifiers)' != ''" />
+ <_PostProcessingItem Include="@(_MergedAppBundleDylib -> '$(_AppBundleName)$(AppBundleExtension)/$(_AppContentsRelativePathForPostProcessing)%(Filename)%(Extension)')" Condition="'$(RuntimeIdentifiers)' != ''">
+ $(_AppContainerDir)%(_PostProcessingItem.Identity)
+ $(_AppContainerDir)%(_PostProcessingItem.Identity).dSYM
+ %(Filename).dSYM
+
<_PostProcessingItem Include="$([System.IO.Path]::GetFileName('$(AppBundleDir)'))/$(_NativeExecutableRelativePath)" Condition="'$(IsWatchApp)' != 'true'">
$(_SymbolsListFullPath)
$(_AppBundleName)$(AppBundleExtension).dSYM
diff --git a/runtime/Delegates.cs.t4 b/runtime/Delegates.cs.t4
index c113d2935358..3ad9caacd8e7 100644
--- a/runtime/Delegates.cs.t4
+++ b/runtime/Delegates.cs.t4
@@ -72,7 +72,7 @@ namespace ObjCRuntime {
Write ("\t\t\tif (IsCoreCLR) {\n\t");
}
if (d.SkipManagedStaticRegistrar) {
- Write ("\t\t\tif (!Runtime.IsManagedStaticRegistrar) {\n\t");
+ Write ("\t\t\tif (!Runtime.IsManagedStaticRegistrar && !Runtime.IsTrimmableStaticRegistrar) {\n\t");
}
#>
options->Delegates-><#= d.SimpleEntryPoint #> = (IntPtr) (void *) <#= d.UnmanagedDelegateCast #> &<#= d.SimpleEntryPoint #>;
diff --git a/runtime/delegates.t4 b/runtime/delegates.t4
index 783a278042fe..42bd87081b07 100644
--- a/runtime/delegates.t4
+++ b/runtime/delegates.t4
@@ -674,7 +674,8 @@
new XDelegate ("void *", "IntPtr", "xamarin_lookup_unmanaged_function",
"const char *", "IntPtr", "assembly",
"const char *", "IntPtr", "symbol",
- "int32_t", "int", "id"
+ "int32_t", "int", "id",
+ "const char *", "IntPtr", "objcClassName"
) {
WrappedManagedFunction = "LookupUnmanagedFunction",
},
diff --git a/runtime/runtime.m b/runtime/runtime.m
index 41fbe8ba9264..c955f6c3cae5 100644
--- a/runtime/runtime.m
+++ b/runtime/runtime.m
@@ -136,7 +136,7 @@
enum InitializationFlags : int {
InitializationFlagsIsPartialStaticRegistrar = 0x01,
InitializationFlagsIsManagedStaticRegistrar = 0x02,
- /* unused = 0x04,*/
+ InitializationFlagsIsTrimmableStaticRegistrar = 0x04,
/* unused = 0x08,*/
InitializationFlagsIsSimulator = 0x10,
InitializationFlagsIsCoreCLR = 0x20,
@@ -2633,7 +2633,7 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
}
void
-xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id)
+xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id, const char* objcClassName)
{
if (*function_pointer != NULL)
return;
@@ -2643,7 +2643,7 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
return;
GCHandle exception_gchandle = INVALID_GCHANDLE;
- *function_pointer = xamarin_lookup_unmanaged_function (assembly, symbol, id, &exception_gchandle);
+ *function_pointer = xamarin_lookup_unmanaged_function (assembly, symbol, id, objcClassName, &exception_gchandle);
if (*function_pointer != NULL)
return;
@@ -3133,6 +3133,16 @@ -(struct NSObjectData*) xamarinGetNSObjectData
}
}
+void
+xamarin_set_is_trimmable_static_registrar (bool value)
+{
+ if (value) {
+ options.flags = (InitializationFlags) (options.flags | InitializationFlagsIsTrimmableStaticRegistrar);
+ } else {
+ options.flags = (InitializationFlags) (options.flags & ~InitializationFlagsIsTrimmableStaticRegistrar);
+ }
+}
+
bool
xamarin_is_managed_exception_marshaling_disabled ()
{
diff --git a/runtime/xamarin/runtime.h b/runtime/xamarin/runtime.h
index 5323ffe95a51..fd5c697efff5 100644
--- a/runtime/xamarin/runtime.h
+++ b/runtime/xamarin/runtime.h
@@ -256,6 +256,7 @@ void xamarin_check_objc_type (id obj, Class expected_class, SEL sel, id self,
#endif
void xamarin_set_is_managed_static_registrar (bool value);
+void xamarin_set_is_trimmable_static_registrar (bool value);
void xamarin_process_nsexception (NSException *exc);
void xamarin_process_nsexception_using_mode (NSException *ns_exception, bool throwManagedAsDefault, GCHandle *output_exception);
@@ -308,7 +309,7 @@ bool xamarin_is_user_type (Class cls);
* symbol: the symbol to look up. Can be NULL to save space (this value isn't used except in error messages).
* id: a numerical id for faster lookup (than doing string comparisons on the symbol name).
*/
-void xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id);
+void xamarin_registrar_dlsym (void **function_pointer, const char *assembly, const char *symbol, int32_t id, const char* objcClassName);
/*
* Wrapper GCHandle functions that takes pointer sized handles instead of ints,
diff --git a/scripts/rsp-to-csproj/rsp-to-csproj.cs b/scripts/rsp-to-csproj/rsp-to-csproj.cs
index a610a06d9570..1bfc7e7c848a 100644
--- a/scripts/rsp-to-csproj/rsp-to-csproj.cs
+++ b/scripts/rsp-to-csproj/rsp-to-csproj.cs
@@ -219,7 +219,10 @@ void ProcessFile (string file)
sb.AppendLine ($" ");
sb.AppendLine ($" ");
foreach (var item in items) {
- sb.AppendLine ($" <{item.Name} Include=\"{item.Include}\" />");
+ string link = "";
+ if (item.Include.StartsWith (workingDirectory))
+ link = $" Link=\"{item.Include [(workingDirectory.Length + 1)..]}\"";
+ sb.AppendLine ($" <{item.Name} Include=\"{item.Include}\"{link} />");
}
sb.AppendLine ($" ");
sb.AppendLine ($"");
diff --git a/src/Foundation/NSObject2.cs b/src/Foundation/NSObject2.cs
index a303621f5e77..e15f95c8c00e 100644
--- a/src/Foundation/NSObject2.cs
+++ b/src/Foundation/NSObject2.cs
@@ -373,6 +373,10 @@ public void Dispose ()
[UnconditionalSuppressMessage ("", "IL2072", Justification = "The APIs this method tries to access are marked by other means, so this is linker-safe.")]
internal static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, Flags flags)
{
+ // This method should never be called when using the trimmable static registrar, so assert that never happens by throwing an exception in that case.
+ if (Runtime.IsTrimmableStaticRegistrar)
+ throw new System.Diagnostics.UnreachableException ();
+
// Note that the code in this method doesn't necessarily work with NativeAOT, so assert that never happens by throwing an exception if using the managed static registrar (which is required for NativeAOT)
if (Runtime.IsManagedStaticRegistrar) {
throw new System.Diagnostics.UnreachableException ();
diff --git a/src/ILLink.Substitutions.MacCatalyst.xml b/src/ILLink.Substitutions.MacCatalyst.xml
index c139f91583b5..7967b89f7039 100644
--- a/src/ILLink.Substitutions.MacCatalyst.xml
+++ b/src/ILLink.Substitutions.MacCatalyst.xml
@@ -10,6 +10,8 @@
+
+
diff --git a/src/ILLink.Substitutions.iOS.xml b/src/ILLink.Substitutions.iOS.xml
index de3ee88011ff..a6cae5234d43 100644
--- a/src/ILLink.Substitutions.iOS.xml
+++ b/src/ILLink.Substitutions.iOS.xml
@@ -12,6 +12,8 @@
+
+
diff --git a/src/ILLink.Substitutions.macOS.xml b/src/ILLink.Substitutions.macOS.xml
index 1ad679b886f2..aa69619fcc9a 100644
--- a/src/ILLink.Substitutions.macOS.xml
+++ b/src/ILLink.Substitutions.macOS.xml
@@ -9,6 +9,8 @@
+
+
diff --git a/src/ILLink.Substitutions.tvOS.xml b/src/ILLink.Substitutions.tvOS.xml
index 68854b87bcab..775071e00939 100644
--- a/src/ILLink.Substitutions.tvOS.xml
+++ b/src/ILLink.Substitutions.tvOS.xml
@@ -12,6 +12,8 @@
+
+
diff --git a/src/ObjCRuntime/Blocks.cs b/src/ObjCRuntime/Blocks.cs
index e492ab7307cc..be694cb1c7eb 100644
--- a/src/ObjCRuntime/Blocks.cs
+++ b/src/ObjCRuntime/Blocks.cs
@@ -511,6 +511,10 @@ public static bool IsManagedBlock (IntPtr block)
[UnconditionalSuppressMessage ("", "IL2072", Justification = "The APIs this method tries to access are marked by other means, so this is linker-safe.")]
static Type? GetDelegateProxyType (MethodInfo minfo, uint token_ref, out MethodInfo? baseMethod)
{
+ // This method should never be called when using the trimmable static registrar, so assert that never happens by throwing an exception in that case.
+ if (Runtime.IsTrimmableStaticRegistrar)
+ throw new System.Diagnostics.UnreachableException ();
+
// Note that the code in this method doesn't necessarily work with NativeAOT, so assert that never happens by throwing an exception if using the managed static registrar (which is required for NativeAOT)
if (Runtime.IsManagedStaticRegistrar)
throw new System.Diagnostics.UnreachableException ();
@@ -610,6 +614,10 @@ static IntPtr CreateBlockForDelegate (Delegate @delegate, Delegate delegateProxy
[UnconditionalSuppressMessage ("", "IL2075", Justification = "The APIs this method tries to access are marked by other means, so this is linker-safe.")]
internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object? @delegate, uint token_ref, string? signature)
{
+ // This method should never be called when using the trimmable static registrar, so assert that never happens by throwing an exception in that case.
+ if (Runtime.IsTrimmableStaticRegistrar)
+ throw new System.Diagnostics.UnreachableException ();
+
// Note that the code in this method doesn't necessarily work with NativeAOT, so assert that never happens by throwing an exception if using the managed static registrar (which is required for NativeAOT)
if (Runtime.IsManagedStaticRegistrar)
throw new System.Diagnostics.UnreachableException ();
diff --git a/src/ObjCRuntime/Class.cs b/src/ObjCRuntime/Class.cs
index bf50b4aa97fc..82c0d85be68a 100644
--- a/src/ObjCRuntime/Class.cs
+++ b/src/ObjCRuntime/Class.cs
@@ -6,6 +6,7 @@
//
// #define LOG_TYPELOAD
+// #define LOG_TRIMMABLE_TYPEMAP
#nullable enable
@@ -136,8 +137,7 @@ public NativeHandle SuperClass {
///
public string? Name {
get {
- var ptr = class_getName (Handle);
- return Marshal.PtrToStringAuto (ptr);
+ return GetClassName (Handle);
}
}
@@ -290,7 +290,7 @@ internal static Type Lookup (IntPtr klass)
return Runtime.Registrar.Lookup (klass, throw_on_error);
if (throw_on_error)
- throw ErrorHelper.CreateError (8026, $"Can't lookup the Objective-C class 0x{klass.ToString ("x")} ({Marshal.PtrToStringAuto (class_getName (klass))}) when the dynamic registrar has been linked away.");
+ throw ErrorHelper.CreateError (8026, $"Can't lookup the Objective-C class 0x{klass.ToString ("x")} ({GetClassName (klass)}) when the dynamic registrar has been linked away.");
return null;
}
@@ -314,6 +314,20 @@ static string GetAssemblyName (Assembly assembly)
// Find the given managed type in the tables generated by the static registrar.
unsafe static IntPtr FindClass (Type type, out bool is_custom_type)
{
+ if (Runtime.IsTrimmableStaticRegistrar) {
+ var attrib = type.GetCustomAttribute ();
+ if (attrib is not null)
+ return attrib.GetClassHandle (out is_custom_type);
+
+ // The type we're looking for might be a type the registrar skipped, in which case we must
+ // find it in the mapping of skipped types.
+ if (TypeMaps.SkippedProxyTypes.TryGetValue (type, out var actualType))
+ return FindClass (actualType, out is_custom_type);
+
+ is_custom_type = false;
+ return IntPtr.Zero;
+ }
+
var map = Runtime.options->RegistrationMap;
is_custom_type = false;
@@ -355,7 +369,7 @@ unsafe static IntPtr FindClass (Type type, out bool is_custom_type)
var rv = class_map.handle;
is_custom_type = (class_map.flags & Runtime.MTTypeFlags.CustomType) == Runtime.MTTypeFlags.CustomType;
#if LOG_TYPELOAD
- Runtime.NSLog ($"FindClass ({type.FullName}, {is_custom_type}): 0x{rv.ToString ("x")} = {Marshal.PtrToStringAuto (class_getName (rv))}.");
+ Runtime.NSLog ($"FindClass ({type.FullName}, {is_custom_type}): 0x{rv.ToString ("x")} = {GetClassName (rv)}.");
#endif
return rv;
}
@@ -433,19 +447,85 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
return -1;
}
+ internal static bool TryGetTrimmableProxyTypeAttribute (string? className, [NotNullWhen (true)] out NSObjectProxyAttribute? proxyAttribute, [NotNullWhen (true)] out Type? managedType)
+ {
+ proxyAttribute = null;
+ managedType = null;
+
+ if (string.IsNullOrEmpty (className)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"GetTrimmableProxyTypeAttribute ({className}) = no class name provided");
+#endif
+ return false;
+ }
+
+ if (!TypeMaps.NSObjectTypes.TryGetValue (className, out managedType)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"GetTrimmableProxyTypeAttribute ({className}) not found in type map");
+#endif
+ return false;
+ }
+
+ if (!TypeMaps.NSObjectProxyTypes.TryGetValue (managedType, out var proxyType)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"GetTrimmableProxyTypeAttribute ({className}) found in type map, but proxy type not found");
+#endif
+ return false;
+ }
+
+ proxyAttribute = proxyType.GetCustomAttribute ();
+ if (proxyAttribute is null) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"GetTrimmableProxyTypeAttribute ({className}) found in proxy type map, but could not create proxy attribute for it");
+#endif
+ return false;
+ }
+
+ return proxyAttribute is not null;
+ }
+
+ static Type? FindTypeInTrimmableMap (NativeHandle @class, out bool is_custom_type)
+ {
+ is_custom_type = false;
+
+ var className = GetClassName (@class);
+ if (!TryGetTrimmableProxyTypeAttribute (className, out var attrib, out var managedType)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"FindType (0x{@class:X} = {className}) could not get proxy attribute");
+#endif
+ return null;
+ }
+
+ var ch = attrib.GetClassHandle (out is_custom_type);
+ if (ch != @class) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"FindType (0x{@class:X} = {className}) found in proxy type map, and attribute, but attribute's class handle doesn't match (0x{ch:X} != 0x{@class:X})");
+#endif
+ }
+
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"FindType (0x{@class:X} = {className}) found {managedType}");
+#endif
+
+ return managedType;
+ }
+
internal unsafe static Type? FindType (NativeHandle @class, out bool is_custom_type)
{
+ if (Runtime.IsTrimmableStaticRegistrar)
+ return FindTypeInTrimmableMap (@class, out is_custom_type);
+
var map = Runtime.options->RegistrationMap;
#if LOG_TYPELOAD
- Runtime.NSLog ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))})");
+ Runtime.NSLog ($"FindType (0x{@class:X} = {GetClassName (@class)})");
#endif
is_custom_type = false;
if (map is null) {
#if LOG_TYPELOAD
- Runtime.NSLog ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => found no map.");
+ Runtime.NSLog ($"FindType (0x{@class:X} = {GetClassName (@class)}) => found no map.");
#endif
return null;
}
@@ -454,12 +534,12 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
var mapIndex = FindMapIndex (map->map, 0, map->map_count - 1, @class);
if (mapIndex == -1) {
#if LOG_TYPELOAD
- Runtime.NSLog ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => found no type.");
+ Runtime.NSLog ($"FindType (0x{@class:X} = {GetClassName (@class)}) => found no type.");
#endif
return null;
}
#if LOG_TYPELOAD
- Runtime.NSLog ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => found index {mapIndex}.");
+ Runtime.NSLog ($"FindType (0x{@class:X} = {GetClassName (@class)}) => found index {mapIndex}.");
#endif
is_custom_type = (map->map [mapIndex].flags & Runtime.MTTypeFlags.CustomType) == Runtime.MTTypeFlags.CustomType;
@@ -467,7 +547,7 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
var type = class_to_type [mapIndex];
if (type is not null) {
#if LOG_TYPELOAD
- Runtime.NSLog ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => found type {type.FullName} for map index {mapIndex}.");
+ Runtime.NSLog ($"FindType (0x{@class:X} = {GetClassName (@class)}) => found type {type.FullName} for map index {mapIndex}.");
#endif
return type;
}
@@ -477,7 +557,7 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
type = ResolveTypeTokenReference (type_reference);
#if LOG_TYPELOAD
- Runtime.NSLog ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => {type?.FullName}; is custom: {is_custom_type} (token reference: 0x{type_reference:X}).");
+ Runtime.NSLog ($"FindType (0x{@class:X} = {GetClassName (@class)}) => {type?.FullName}; is custom: {is_custom_type} (token reference: 0x{type_reference:X}).");
#endif
class_to_type [mapIndex] = type;
@@ -562,6 +642,10 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
static MemberInfo? ResolveToken (Assembly assembly, Module? module, uint token)
{
+ // This method should never be called when using the trimmable static registrar, so assert that never happens by throwing an exception in that case.
+ if (Runtime.IsTrimmableStaticRegistrar)
+ throw new System.Diagnostics.UnreachableException ();
+
if (!Runtime.IsManagedStaticRegistrar)
return ResolveTokenNonManagedStatic (assembly, module, token);
@@ -589,6 +673,10 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
[UnconditionalSuppressMessage ("", "IL2026", Justification = "The APIs this method tries to access are marked by other means, so this is linker-safe.")]
static MemberInfo? ResolveTokenNonManagedStatic (Assembly assembly, Module? module, uint token)
{
+ // This method should never be called when using the trimmable static registrar, so assert that never happens by throwing an exception in that case.
+ if (Runtime.IsTrimmableStaticRegistrar)
+ throw new System.Diagnostics.UnreachableException ();
+
// This method should never be called when using the managed static registrar, so assert that never happens by throwing an exception in that case.
// This also takes care of NativeAOT, because the managed static registrar is required when using NativeAOT.
if (Runtime.IsManagedStaticRegistrar)
@@ -869,6 +957,12 @@ internal static bool class_addMethod (IntPtr cls, IntPtr name, IntPtr imp, strin
[DllImport (Messaging.LIBOBJC_DYLIB)]
internal static extern IntPtr class_getName (IntPtr cls);
+ static string? GetClassName (IntPtr cls)
+ {
+ var namePtr = class_getName (cls);
+ return Marshal.PtrToStringAuto (namePtr);
+ }
+
[DllImport (Messaging.LIBOBJC_DYLIB)]
internal static extern IntPtr class_getSuperclass (IntPtr cls);
diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs
index 3e7c62a06ecb..173bf5645c4d 100644
--- a/src/ObjCRuntime/Registrar.cs
+++ b/src/ObjCRuntime/Registrar.cs
@@ -148,6 +148,10 @@ internal class ObjCType {
public bool IsCategory { get { return CategoryAttribute is not null; } }
+ public bool IsStubClass {
+ get => RegisterAttribute?.IsStubClass == true;
+ }
+
public ObjCType (Registrar registrar, TType type)
{
this.Registrar = registrar;
diff --git a/src/ObjCRuntime/RegistrarHelper.cs b/src/ObjCRuntime/RegistrarHelper.cs
index e334ebf10c59..6cafab3bec2b 100644
--- a/src/ObjCRuntime/RegistrarHelper.cs
+++ b/src/ObjCRuntime/RegistrarHelper.cs
@@ -173,7 +173,7 @@ static void Register (IManagedRegistrar registrar)
static Stopwatch? lookupWatch;
#endif
- internal static IntPtr LookupUnmanagedFunction (IntPtr assembly, string? symbol, int id)
+ internal static IntPtr LookupUnmanagedFunction (IntPtr assembly, string? symbol, int id, string? objcClassName)
{
IntPtr rv;
@@ -200,7 +200,39 @@ internal static IntPtr LookupUnmanagedFunction (IntPtr assembly, string? symbol,
if (rv != IntPtr.Zero)
return rv;
- throw ErrorHelper.CreateError (8001, "Unable to find the managed function with id {0} ({1})", id, symbol);
+ if (!string.IsNullOrEmpty (objcClassName)) {
+ rv = LookupUnmanagedFunctionInType (objcClassName, symbol);
+ }
+
+#if TRACE
+ lookupWatch.Stop ();
+
+ Console.WriteLine ("LookupUnmanagedFunction (0x{0} = {1}, {2}, {3}) => 0x{4} ElapsedMilliseconds: {5}", assembly.ToString ("x"), Marshal.PtrToStringAuto (assembly), symbol, id, rv.ToString ("x"), lookupWatch.ElapsedMilliseconds);
+#endif
+
+ if (rv != IntPtr.Zero)
+ return rv;
+
+ throw ErrorHelper.CreateError (8001, "Unable to find the managed function with id {0} ({1}, {2})", id, symbol, objcClassName);
+ }
+
+ static IntPtr LookupUnmanagedFunctionInType (string objcTypeName, string? symbol)
+ {
+ if (!Class.TryGetTrimmableProxyTypeAttribute (objcTypeName, out var attrib, out var _)) {
+#if TRACE
+ Console.WriteLine ($"LookupUnmanagedFunctionInType ({objcTypeName}, {symbol}) could not find proxy type");
+#endif
+ return IntPtr.Zero;
+ }
+
+
+ var rv = attrib.LookupUnmanagedFunction (symbol);
+
+#if TRACE
+ Console.WriteLine ($"LookupUnmanagedFunctionInType ({objcTypeName}, {symbol}) called {attrib.GetType ().FullName}::LookupUnmanagedFunction, got 0x{rv:x} back");
+#endif
+
+ return rv;
}
static IntPtr LookupUnmanagedFunctionInAssembly (IntPtr assembly_name, string? symbol, int id)
diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs
index 7f63bdc3c785..28fbf852cef9 100644
--- a/src/ObjCRuntime/Runtime.cs
+++ b/src/ObjCRuntime/Runtime.cs
@@ -164,7 +164,7 @@ internal struct Trampolines {
internal enum InitializationFlags : int {
IsPartialStaticRegistrar = 0x01,
IsManagedStaticRegistrar = 0x02,
- /* unused = 0x04,*/
+ IsTrimmableStaticRegistrar = 0x04,
/* unused = 0x08,*/
IsSimulator = 0x10,
IsCoreCLR = 0x20,
@@ -251,6 +251,14 @@ internal unsafe static bool IsManagedStaticRegistrar {
}
}
+ [BindingImpl (BindingImplOptions.Optimizable)]
+ internal unsafe static bool IsTrimmableStaticRegistrar {
+ get {
+ // The linker may turn calls to this property into a constant
+ return options->Flags.HasFlag (InitializationFlags.IsTrimmableStaticRegistrar);
+ }
+ }
+
/// If dynamic registration is supported.
/// If dynamic registration is supported.
///
@@ -298,6 +306,11 @@ unsafe static void SafeInitialize (InitializationOptions* options, IntPtr* excep
Initialize (options);
} catch (Exception e) {
*exception_gchandle = AllocGCHandle (e);
+ try {
+ Runtime.NSLog ($"Failed to initialize the runtime: {e}");
+ } catch {
+ // ignore any exceptions here
+ }
}
}
@@ -337,6 +350,11 @@ unsafe static void Initialize (InitializationOptions* options)
block_lifetime_table = new ConditionalWeakTable ();
lock_obj = new object ();
+#if NET11_0_OR_GREATER
+ if (IsTrimmableStaticRegistrar)
+ TypeMaps.Initialize ();
+#endif
+
NSObjectClass = NSObject.Initialize ();
if (DynamicRegistrationSupported) {
@@ -1334,6 +1352,41 @@ static void AppendAdditionalInformation (StringBuilder msg, IntPtr sel, RuntimeM
if (type is null)
throw new ArgumentNullException (nameof (type));
+ if (Runtime.IsTrimmableStaticRegistrar) {
+ var lookupType = type;
+ if (typeof (T) == type && type.IsGenericType) {
+ var inst = ConstructNSObjectViaFactoryMethod (ptr);
+ if (inst is not null) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructNSObject<{typeof (T).FullName}> (0x{@ptr:X}, {type}) created '{inst.GetType ().FullName}' instance using static interface factory method.");
+#endif
+ return inst;
+ }
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructNSObject<{typeof (T).FullName}> (0x{@ptr:X}, {type}) failed to create instance using static interface factory method.");
+#endif
+ CannotCreateManagedInstanceOfGenericType (ptr, IntPtr.Zero, type, missingCtorResolution, sel, method_handle);
+ return null;
+ }
+
+ if (TypeMaps.NSObjectProxyTypes.TryGetValue (lookupType, out var proxyType)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructNSObject<{typeof (T).FullName}> (0x{@ptr:X}, {type}) found in proxy map with type '{proxyType.FullName}' for lookup type '{lookupType.FullName}'");
+#endif
+ var attrib = proxyType.GetCustomAttribute ();
+ if (attrib is null)
+ throw new InvalidOperationException ($"Type '{proxyType.FullName}' is expected to have an NSObjectProxyAttribute."); // TODO: better exception
+ var instance = (T?) (object?) attrib.CreateObject (ptr);
+ if (instance is not null)
+ return instance;
+ }
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructNSObject<{typeof (T).FullName}> (0x{@ptr:X}, {type}) did not find type '{lookupType.FullName}' in proxy map");
+#endif
+ MissingCtor (ptr, IntPtr.Zero, type, missingCtorResolution, sel, method_handle);
+ return null;
+ }
+
if (Runtime.IsManagedStaticRegistrar) {
T? instance = default;
var nativeHandle = new NativeHandle (ptr);
@@ -1412,6 +1465,58 @@ static void AppendAdditionalInformation (StringBuilder msg, IntPtr sel, RuntimeM
if (type.IsByRef)
type = type.GetElementType ()!;
+ if (Runtime.IsTrimmableStaticRegistrar) {
+ if (typeof (T) == type && type.IsGenericType) {
+ var inst = ConstructINativeObjectViaFactoryMethod (ptr, owns);
+ if (inst is not null) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructINativeObject<{typeof (T).FullName}> (0x{@ptr:X}, {type}) created '{inst.GetType ().FullName}' instance using static interface factory method.");
+#endif
+ return inst;
+ }
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructINativeObject<{typeof (T).FullName}> (0x{@ptr:X}, {type}) failed to create instance using static interface factory method.");
+#endif
+ CannotCreateManagedInstanceOfGenericType (ptr, IntPtr.Zero, type, missingCtorResolution, sel, method_handle);
+ return default (T);
+ }
+ if (TypeMaps.NSObjectProxyTypes.TryGetValue (type, out var proxyType)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructINativeObject<{typeof (T).FullName}> (0x{@ptr:X}, {type.FullName}) found in proxy map");
+#endif
+ var attrib = proxyType.GetCustomAttribute ();
+ if (attrib is null)
+ throw new InvalidOperationException ($"Type '{proxyType.FullName}' is expected to have an NSObjectProxyAttribute."); // TODO: better exception
+ var rv = (T?) (object?) attrib.CreateObject (ptr);
+ if (owns)
+ Runtime.TryReleaseINativeObject (rv);
+ return rv;
+ }
+ if (TypeMaps.ProtocolProxyTypes.TryGetValue (type, out var protocolProxyType)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructINativeObject<{typeof (T).FullName}> (0x{@ptr:X}, {type.FullName}) found in protocol proxy map");
+#endif
+ var attrib = protocolProxyType.GetCustomAttribute ();
+ if (attrib is null)
+ throw new InvalidOperationException ($"Type '{protocolProxyType.FullName}' is expected to have an ProtocolProxyAttribute."); // TODO: better exception
+ return (T?) (object?) attrib.CreateObject (ptr, owns);
+ }
+ if (TypeMaps.INativeObjectProxyTypes.TryGetValue (type, out var inativeObjectProxyType)) {
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructINativeObject<{typeof (T).FullName}> (0x{@ptr:X}, {type.FullName}) found in INativeObject proxy map");
+#endif
+ var attrib = inativeObjectProxyType.GetCustomAttribute ();
+ if (attrib is null)
+ throw new InvalidOperationException ($"Type '{inativeObjectProxyType.FullName}' is expected to have an INativeObjectProxyAttribute."); // TODO: better exception
+ return (T?) (object?) attrib.CreateObject (ptr, owns);
+ }
+#if LOG_TRIMMABLE_TYPEMAP
+ Runtime.NSLog ($"ConstructINativeObject<{typeof (T).FullName}> (0x{@ptr:X}) did not find type '{type.FullName}' in any map");
+#endif
+ MissingCtor (ptr, IntPtr.Zero, type, missingCtorResolution, sel, method_handle);
+ return default (T);
+ }
+
if (Runtime.IsManagedStaticRegistrar) {
var nativeHandle = new NativeHandle (ptr);
T? instance = default (T);
@@ -2016,7 +2121,7 @@ static Type LookupINativeObjectImplementation (IntPtr ptr, Type target_type, Typ
// native objects and NSObject instances.
throw ErrorHelper.CreateError (8004, $"Cannot create an instance of {implementation.FullName} for the native object 0x{ptr:x} (of type '{Class.class_getName (Class.GetClassForObject (ptr))}'), because another instance already exists for this native object (of type {o.GetType ().FullName}).");
}
- if (!Runtime.IsManagedStaticRegistrar) {
+ if (!Runtime.IsManagedStaticRegistrar && !Runtime.IsTrimmableStaticRegistrar) {
// For other registrars other than managed-static the generic parameter of ConstructNSObject is used
// only to cast the return value so we can safely pass NSObject here to satisfy the constraints of the
// generic parameter.
@@ -2065,6 +2170,9 @@ static void TryReleaseINativeObject (INativeObject? obj)
var rv = RegistrarHelper.FindProtocolWrapperType (type);
if (rv is not null)
return rv;
+ } else if (IsTrimmableStaticRegistrar) {
+ if (TypeMaps.ProtocolWrapperTypes.TryGetValue (type, out var protocolWrapperType))
+ return protocolWrapperType;
} else {
unsafe {
var map = options->RegistrationMap;
@@ -2684,9 +2792,9 @@ static nint InvokeConformsToProtocol (IntPtr gchandle, IntPtr handle, IntPtr pro
return rv ? 1 : 0;
}
- static IntPtr LookupUnmanagedFunction (IntPtr assembly, IntPtr symbol, int id)
+ static IntPtr LookupUnmanagedFunction (IntPtr assembly, IntPtr symbol, int id, IntPtr objcClassName)
{
- return RegistrarHelper.LookupUnmanagedFunction (assembly, Marshal.PtrToStringAuto (symbol), id);
+ return RegistrarHelper.LookupUnmanagedFunction (assembly, Marshal.PtrToStringAuto (symbol), id, Marshal.PtrToStringAuto (objcClassName));
}
}
diff --git a/src/ObjCRuntime/TypeMaps.cs b/src/ObjCRuntime/TypeMaps.cs
new file mode 100644
index 000000000000..97d6dc1b1538
--- /dev/null
+++ b/src/ObjCRuntime/TypeMaps.cs
@@ -0,0 +1,146 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+namespace ObjCRuntime;
+
+// The trimmable static registrar makes this type public when needed.
+abstract class NSObjectProxyAttribute : Attribute {
+ protected NSObjectProxyAttribute () { }
+
+ public abstract NSObject? CreateObject (IntPtr handle);
+ public abstract IntPtr GetClassHandle (out bool is_custom_type);
+ public abstract IntPtr LookupUnmanagedFunction (string? name);
+}
+
+// The trimmable static registrar makes this type public when needed.
+abstract class ProtocolProxyAttribute : Attribute {
+ public abstract INativeObject? CreateObject (IntPtr handle, bool owns);
+}
+
+// The trimmable static registrar makes this type public when needed.
+abstract class INativeObjectProxyAttribute : Attribute {
+ public abstract INativeObject? CreateObject (IntPtr handle, bool owns);
+}
+
+// The trimmable static registrar makes this type public when needed.
+sealed class SkippedObjectiveCTypeUniverse {
+ SkippedObjectiveCTypeUniverse () { }
+}
+
+static class TypeMaps {
+#if NET11_0_OR_GREATER
+#pragma warning disable 8618 // "Non-nullable field '...' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.": we make sure through other means that these will never be null
+ internal static IReadOnlyDictionary NSObjectTypes;
+ internal static IReadOnlyDictionary SkippedProxyTypes;
+ internal static IReadOnlyDictionary NSObjectProxyTypes;
+ internal static IReadOnlyDictionary INativeObjectProxyTypes;
+ internal static IReadOnlyDictionary ProtocolProxyTypes;
+ internal static IReadOnlyDictionary ProtocolWrapperTypes;
+#pragma warning restore 8618
+
+ internal static void Initialize ()
+ {
+ NSObjectTypes = TypeMapping.GetOrCreateExternalTypeMapping ();
+ SkippedProxyTypes = TypeMapping.GetOrCreateProxyTypeMapping ();
+ NSObjectProxyTypes = TypeMapping.GetOrCreateProxyTypeMapping ();
+ INativeObjectProxyTypes = TypeMapping.GetOrCreateProxyTypeMapping ();
+ ProtocolProxyTypes = TypeMapping.GetOrCreateProxyTypeMapping ();
+ ProtocolWrapperTypes = TypeMapping.GetOrCreateProxyTypeMapping ();
+ }
+#else
+ static IReadOnlyDictionary? nsobject_types;
+ internal static IReadOnlyDictionary NSObjectTypes {
+ get {
+ if (nsobject_types is null)
+ Initialize ();
+ return nsobject_types;
+ }
+ }
+
+ static IReadOnlyDictionary? skipped_proxy_types;
+ internal static IReadOnlyDictionary SkippedProxyTypes {
+ get {
+ if (skipped_proxy_types is null)
+ Initialize ();
+ return skipped_proxy_types;
+ }
+ }
+
+ static IReadOnlyDictionary? nsobject_proxy_types;
+ internal static IReadOnlyDictionary NSObjectProxyTypes {
+ get {
+ if (nsobject_proxy_types is null)
+ Initialize ();
+ return nsobject_proxy_types;
+ }
+ }
+
+ static IReadOnlyDictionary? inativeobject_proxy_types;
+ internal static IReadOnlyDictionary INativeObjectProxyTypes {
+ get {
+ if (inativeobject_proxy_types is null)
+ Initialize ();
+ return inativeobject_proxy_types;
+ }
+ }
+
+ static IReadOnlyDictionary? protocol_proxy_types;
+ internal static IReadOnlyDictionary ProtocolProxyTypes {
+ get {
+ if (protocol_proxy_types is null)
+ Initialize ();
+ return protocol_proxy_types;
+ }
+ }
+
+ static IReadOnlyDictionary? protocol_wrapper_types;
+ internal static IReadOnlyDictionary ProtocolWrapperTypes {
+ get {
+ if (protocol_wrapper_types is null)
+ Initialize ();
+ return protocol_wrapper_types;
+ }
+ }
+
+ static object lock_obj = new object ();
+
+ [MemberNotNull (nameof (nsobject_types))]
+ [MemberNotNull (nameof (skipped_proxy_types))]
+ [MemberNotNull (nameof (nsobject_proxy_types))]
+ [MemberNotNull (nameof (inativeobject_proxy_types))]
+ [MemberNotNull (nameof (protocol_proxy_types))]
+ [MemberNotNull (nameof (protocol_wrapper_types))]
+ internal static void Initialize ()
+ {
+ // In .NET 10 we can only create the type maps from the entry assembly, which can only be done after calling the
+ // main assembly's Main method - so we need to create the type maps on demand, instead of from Runtime.Initialize.
+ // For reference, this is what happens:
+ // System.InvalidOperationException: Entry assembly is required but was not found.
+ // at System.Runtime.InteropServices.TypeMapLazyDictionary.CreateMaps(RuntimeType groupType, newExternalTypeEntry, newProxyTypeEntry)
+ // at System.Runtime.InteropServices.TypeMapLazyDictionary.CreateExternalTypeMap(RuntimeType groupType)
+ lock (lock_obj) {
+ if (nsobject_types is null)
+ nsobject_types = TypeMapping.GetOrCreateExternalTypeMapping ();
+
+ if (skipped_proxy_types is null)
+ skipped_proxy_types = TypeMapping.GetOrCreateProxyTypeMapping ();
+
+ if (nsobject_proxy_types is null)
+ nsobject_proxy_types = TypeMapping.GetOrCreateProxyTypeMapping ();
+
+ if (inativeobject_proxy_types is null)
+ inativeobject_proxy_types = TypeMapping.GetOrCreateProxyTypeMapping ();
+
+ if (protocol_proxy_types is null)
+ protocol_proxy_types = TypeMapping.GetOrCreateProxyTypeMapping ();
+
+ if (protocol_wrapper_types is null)
+ protocol_wrapper_types = TypeMapping.GetOrCreateProxyTypeMapping ();
+ }
+ }
+#endif // NET11_0_OR_GREATER
+}
+
diff --git a/src/frameworks.sources b/src/frameworks.sources
index 6573e8e10f1b..443c2c13f93f 100644
--- a/src/frameworks.sources
+++ b/src/frameworks.sources
@@ -1952,6 +1952,7 @@ SHARED_SOURCES = \
ObjCRuntime/TrampolineBlockBase.cs \
ObjCRuntime/TransientAttribute.cs \
ObjCRuntime/TypeConverter.cs \
+ ObjCRuntime/TypeMaps.cs \
ObjCRuntime/UserDelegateTypeAttribute.cs \
System.Net.Http/CFContentStream.cs \
System.Net.Http/CFNetworkHandler.cs \
diff --git a/tests/generator/Asserts.cs b/tests/bgen/Asserts.cs
similarity index 100%
rename from tests/generator/Asserts.cs
rename to tests/bgen/Asserts.cs
diff --git a/tests/generator/AttributeFactoryTests.cs b/tests/bgen/AttributeFactoryTests.cs
similarity index 73%
rename from tests/generator/AttributeFactoryTests.cs
rename to tests/bgen/AttributeFactoryTests.cs
index 096f3bc60e98..ebc3b2a4ff06 100644
--- a/tests/generator/AttributeFactoryTests.cs
+++ b/tests/bgen/AttributeFactoryTests.cs
@@ -13,11 +13,11 @@ static void AssertAttributeCreation (Func
{
var typeName = typeof (T).Name;
var attr = callback (platform, major, minor, message) as T;
- Assert.IsNotNull (attr, $"{typeName} attribute type");
- Assert.AreEqual (platform, attr.Platform, $"{typeName} Platform");
- Assert.AreEqual (major, attr.Version!.Major, $"{typeName} Major");
- Assert.AreEqual (minor, attr.Version!.Minor, $"{typeName} Minor");
- Assert.AreEqual (message, attr.Message);
+ Assert.That (attr, Is.Not.Null, $"{typeName} attribute type");
+ Assert.That (attr.Platform, Is.EqualTo (platform), $"{typeName} Platform");
+ Assert.That (attr.Version!.Major, Is.EqualTo (major), $"{typeName} Major");
+ Assert.That (attr.Version!.Minor, Is.EqualTo (minor), $"{typeName} Minor");
+ Assert.That (attr.Message, Is.EqualTo (message));
}
static void AssertAttributeCreationNotVersion (Func callback, PlatformName platform,
@@ -25,9 +25,9 @@ static void AssertAttributeCreationNotVersion (Func
{
var typeName = typeof (T).Name;
var attr = callback (platform, message) as T;
- Assert.IsNotNull (attr, $"{typeName} attribute type");
- Assert.AreEqual (platform, attr.Platform, $"{typeName} Platform");
- Assert.AreEqual (message, attr.Message);
+ Assert.That (attr, Is.Not.Null, $"{typeName} attribute type");
+ Assert.That (attr.Platform, Is.EqualTo (platform), $"{typeName} Platform");
+ Assert.That (attr.Message, Is.EqualTo (message));
}
@@ -58,14 +58,14 @@ public void CreateAttributeNoVersionTest (PlatformName platform, string? message
[TestCase (PlatformName.MacOSX)]
[TestCase (PlatformName.TvOS)]
public void CreateNoVersionSupportedAttributeTest (PlatformName platform)
- => Assert.AreEqual (platform, AttributeFactory.CreateNoVersionSupportedAttribute (platform).Platform);
+ => Assert.That (AttributeFactory.CreateNoVersionSupportedAttribute (platform).Platform, Is.EqualTo (platform));
[TestCase (PlatformName.iOS)]
[TestCase (PlatformName.MacCatalyst)]
[TestCase (PlatformName.MacOSX)]
[TestCase (PlatformName.TvOS)]
public void CreateUnsupportedAttributeTest (PlatformName platform)
- => Assert.AreEqual (platform, AttributeFactory.CreateUnsupportedAttribute (platform).Platform);
+ => Assert.That (AttributeFactory.CreateUnsupportedAttribute (platform).Platform, Is.EqualTo (platform));
class CloneCasesNoVersionClass : IEnumerable {
public IEnumerator GetEnumerator ()
@@ -90,9 +90,9 @@ public IEnumerator GetEnumerator ()
public void CloneNoVersionTest (AvailabilityBaseAttribute attributeToClone, PlatformName targetPlatform)
{
var clone = AttributeFactory.CloneFromOtherPlatform (attributeToClone, targetPlatform);
- Assert.AreEqual (targetPlatform, clone.Platform, "platform");
- Assert.AreEqual (attributeToClone.Message, clone.Message, "message");
- Assert.AreEqual (attributeToClone.GetType (), clone.GetType (), "type");
+ Assert.That (clone.Platform, Is.EqualTo (targetPlatform), "platform");
+ Assert.That (clone.Message, Is.EqualTo (attributeToClone.Message), "message");
+ Assert.That (clone.GetType (), Is.EqualTo (attributeToClone.GetType ()), "type");
}
class CloneCasesMinVersionClass : IEnumerable {
@@ -113,13 +113,13 @@ public IEnumerator GetEnumerator ()
public void CloneMinVersion (AvailabilityBaseAttribute attributeToClone, PlatformName targetPlatform)
{
var clone = AttributeFactory.CloneFromOtherPlatform (attributeToClone, targetPlatform);
- Assert.AreEqual (targetPlatform, clone.Platform, "platform");
- Assert.AreEqual (attributeToClone.Message, clone.Message, "message");
- Assert.AreEqual (attributeToClone.GetType (), clone.GetType (), "type");
+ Assert.That (clone.Platform, Is.EqualTo (targetPlatform), "platform");
+ Assert.That (clone.Message, Is.EqualTo (attributeToClone.Message), "message");
+ Assert.That (clone.GetType (), Is.EqualTo (attributeToClone.GetType ()), "type");
if (clone.AvailabilityKind == AvailabilityKind.Introduced) {
- Assert.Null (clone.Version, "Version");
+ Assert.That (clone.Version, Is.Null, "Version");
} else {
- Assert.AreEqual (Xamarin.SdkVersions.GetMinVersion (targetPlatform.AsApplePlatform ()), clone.Version, "Version");
+ Assert.That (clone.Version, Is.EqualTo (Xamarin.SdkVersions.GetMinVersion (targetPlatform.AsApplePlatform ())), "Version");
}
}
@@ -145,10 +145,10 @@ public IEnumerator GetEnumerator ()
public void CloneBuildVersion (AvailabilityBaseAttribute attributeToClone, PlatformName targetPlatform)
{
var clone = AttributeFactory.CloneFromOtherPlatform (attributeToClone, targetPlatform);
- Assert.AreEqual (targetPlatform, clone.Platform, "platform");
- Assert.AreEqual (attributeToClone.Message, clone.Message, "message");
- Assert.AreEqual (attributeToClone.GetType (), clone.GetType (), "type");
- Assert.AreEqual (attributeToClone.Version, clone.Version);
+ Assert.That (clone.Platform, Is.EqualTo (targetPlatform), "platform");
+ Assert.That (clone.Message, Is.EqualTo (attributeToClone.Message), "message");
+ Assert.That (clone.GetType (), Is.EqualTo (attributeToClone.GetType ()), "type");
+ Assert.That (clone.Version, Is.EqualTo (attributeToClone.Version));
}
}
diff --git a/tests/generator/BGenBase.cs b/tests/bgen/BGenBase.cs
similarity index 97%
rename from tests/generator/BGenBase.cs
rename to tests/bgen/BGenBase.cs
index ac409d15a36b..04e3730f99d5 100644
--- a/tests/generator/BGenBase.cs
+++ b/tests/bgen/BGenBase.cs
@@ -43,7 +43,7 @@ internal BGenTool BuildFile (Profile profile, bool nowarnings, Action
TestContext.Out.WriteLine (TestContext.CurrentContext.Test.FullName);
foreach (var filename in filenames)
TestContext.Out.WriteLine ($"\t{filename}");
- bgen.CreateTemporaryBinding (filenames.Select ((filename) => File.ReadAllText (Path.Combine (Configuration.SourceRoot, "tests", "generator", filename))).ToArray ());
+ bgen.CreateTemporaryBinding (filenames.Select ((filename) => File.ReadAllText (Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", filename))).ToArray ());
bgen.AssertExecute ("build");
if (nowarnings)
bgen.AssertNoWarnings ();
diff --git a/tests/generator/BGenTests.cs b/tests/bgen/BGenTests.cs
similarity index 85%
rename from tests/generator/BGenTests.cs
rename to tests/bgen/BGenTests.cs
index a1f1f1064a59..7382ffb73f94 100644
--- a/tests/generator/BGenTests.cs
+++ b/tests/bgen/BGenTests.cs
@@ -104,7 +104,7 @@ public void Bug27986 ()
.Union (allTypes.SelectMany ((type) => type.Properties));
var preserves = allMembers.Count ((v) => v.HasCustomAttributes && v.CustomAttributes.Any ((ca) => ca.AttributeType.Name == "PreserveAttribute"));
- Assert.AreEqual (35, preserves, "Preserve attribute count"); // If you modified code that generates PreserveAttributes please update the preserve count
+ Assert.That (preserves, Is.EqualTo (35), "Preserve attribute count"); // If you modified code that generates PreserveAttributes please update the preserve count
}
[Test]
@@ -140,7 +140,7 @@ public void Bug31788 (Profile profile)
var bgen = new BGenTool ();
bgen.Profile = profile;
bgen.Defines = BGenTool.GetDefaultDefines (bgen.Profile);
- bgen.CreateTemporaryBinding (File.ReadAllText (Path.Combine (Configuration.SourceRoot, "tests", "generator", "bug31788.cs")));
+ bgen.CreateTemporaryBinding (File.ReadAllText (Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", "bug31788.cs")));
bgen.AssertExecute ("build");
bgen.AssertNoWarnings ();
@@ -158,7 +158,7 @@ public void Bug34042 ()
[TestCase (Profile.iOS)]
public void NSCopyingNullability (Profile profile)
{
- var bgen = BuildFile (profile, "tests/nscopying-nullability.cs");
+ var bgen = BuildFile (profile, "nscopying-nullability.cs");
bgen.AssertNoWarnings ();
}
@@ -166,7 +166,7 @@ public void NSCopyingNullability (Profile profile)
[TestCase (Profile.iOS)]
public void EditorBrowsable (Profile profile)
{
- var bgen = BuildFile (profile, false, true, "tests/editor-browsable.cs");
+ var bgen = BuildFile (profile, false, true, "editor-browsable.cs");
var types = bgen.ApiAssembly.MainModule.Types;
var hasEditorBrowsableAttribute = new Func ((ICustomAttributeProvider provider) => {
@@ -174,9 +174,9 @@ public void EditorBrowsable (Profile profile)
});
var strongEnumType = types.Single (v => v.Name == "StrongEnum");
- Assert.IsTrue (hasEditorBrowsableAttribute (strongEnumType), "StrongEnumType");
+ Assert.That (hasEditorBrowsableAttribute (strongEnumType), Is.True, "StrongEnumType");
var objcClassType = types.Single (v => v.Name == "ObjCClass");
- Assert.IsTrue (hasEditorBrowsableAttribute (objcClassType), "ObjCClass");
+ Assert.That (hasEditorBrowsableAttribute (objcClassType), Is.True, "ObjCClass");
}
static string RenderArgument (CustomAttributeArgument arg)
@@ -294,7 +294,7 @@ public void Bug35176 ()
Console.WriteLine (renderedAttributes);
}
- Assert.AreEqual (expectedAttributes, renderedAttributes, "Introduced attributes");
+ Assert.That (renderedAttributes, Is.EqualTo (expectedAttributes), "Introduced attributes");
}
[Test]
@@ -305,8 +305,8 @@ public void INativeObjectsInBlocks (Profile profile)
var bgen = new BGenTool ();
bgen.Profile = profile;
bgen.Defines = BGenTool.GetDefaultDefines (bgen.Profile);
- bgen.AddTestApiDefinition ("tests/inativeobjects-in-blocks.cs");
- bgen.AddExtraSourcesRelativeToGeneratorDirectory ("tests/inativeobjects-in-blocks-sources.cs");
+ bgen.AddTestApiDefinition ("inativeobjects-in-blocks.cs");
+ bgen.AddExtraSourcesRelativeToGeneratorDirectory ("inativeobjects-in-blocks-sources.cs");
bgen.CreateTemporaryBinding ();
bgen.AssertExecute ("build");
bgen.AssertNoWarnings ();
@@ -361,7 +361,7 @@ public void Bug42742 ()
.Union (allTypes.SelectMany ((type) => type.Properties));
var preserves = allMembers.Sum ((v) => v.CustomAttributes.Count ((ca) => ca.AttributeType.Name == "AdviceAttribute"));
- Assert.AreEqual (33, preserves, "Advice attribute count"); // If you modified code that generates AdviceAttributes please update the attribute count
+ Assert.That (preserves, Is.EqualTo (33), "Advice attribute count"); // If you modified code that generates AdviceAttributes please update the attribute count
}
[Test]
@@ -389,7 +389,7 @@ public void Bug46292 (Profile profile)
.Union (allTypes.SelectMany ((type) => type.Properties));
var attribCount = allMembers.Count ((v) => v.HasCustomAttributes && v.CustomAttributes.Any ((ca) => ca.AttributeType.Name == "ObsoleteAttribute"));
- Assert.AreEqual (2, attribCount, "attribute count");
+ Assert.That (attribCount, Is.EqualTo (2), "attribute count");
}
[Test]
@@ -402,7 +402,7 @@ public void Bug53076 ()
// Count all *Async methods whose first parameter is 'IMyFooProtocol'.
var methodCount = allMethods.Count ((v) => v.Name.EndsWith ("Async", StringComparison.Ordinal) && v.Parameters.Count > 0 && v.Parameters [0].ParameterType.Name == "IMyFooProtocol");
- Assert.AreEqual (10, methodCount, "Async method count");
+ Assert.That (methodCount, Is.EqualTo (10), "Async method count");
}
[Test]
@@ -415,7 +415,7 @@ public void Bug53076WithModel ()
// Count all *Async methods whose first parameter is 'IMyFooProtocol'.
var methodCount = allMethods.Count ((v) => v.Name.EndsWith ("Async", StringComparison.Ordinal) && v.Parameters.Count > 0 && v.Parameters [0].ParameterType.Name == "IMyFooProtocol");
- Assert.AreEqual (10, methodCount, "Async method count");
+ Assert.That (methodCount, Is.EqualTo (10), "Async method count");
}
[Test]
@@ -430,7 +430,7 @@ public void StackOverflow20696157 ()
[TestCase (Profile.iOS)]
public void TypesInMultipleNamespaces (Profile profile)
{
- BuildFile (profile, "tests/types-in-multiple-namespaces.cs");
+ BuildFile (profile, "types-in-multiple-namespaces.cs");
}
[Test]
@@ -516,7 +516,7 @@ public void MultipleApiDefinitions2 ()
[TestCase (Profile.iOS)]
public void INativeObjectArraysInBlocks (Profile profile)
{
- BuildFile (profile, "tests/inativeobject-arrays-in-blocks.cs");
+ BuildFile (profile, "inativeobject-arrays-in-blocks.cs");
}
[Test]
@@ -527,8 +527,8 @@ public void ClassNameCollision (Profile profile)
var bgen = new BGenTool ();
bgen.Profile = profile;
bgen.Defines = BGenTool.GetDefaultDefines (bgen.Profile);
- bgen.Sources.Add (Path.Combine (Configuration.SourceRoot, "tests", "generator", "classNameCollision-enum.cs"));
- bgen.ApiDefinitions.Add (Path.Combine (Configuration.SourceRoot, "tests", "generator", "classNameCollision.cs"));
+ bgen.Sources.Add (Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", "classNameCollision-enum.cs"));
+ bgen.ApiDefinitions.Add (Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", "classNameCollision.cs"));
bgen.CreateTemporaryBinding ();
bgen.AssertExecute ("build");
bgen.AssertNoWarnings ();
@@ -576,7 +576,7 @@ public void NoAsyncInternalWrapper (Profile profile)
.Union (allTypes.SelectMany ((type) => type.Fields))
.Union (allTypes.SelectMany ((type) => type.Properties));
- Assert.AreEqual (2, allMembers.Count ((member) => member.Name == "RequiredMethodAsync"), "Expected 2 RequiredMethodAsync members in generated code. If you modified code that generates RequiredMethodAsync (AsyncAttribute) please update the RequiredMethodAsync count.");
+ Assert.That (allMembers.Count ((member) => member.Name == "RequiredMethodAsync"), Is.EqualTo (2), "Expected 2 RequiredMethodAsync members in generated code. If you modified code that generates RequiredMethodAsync (AsyncAttribute) please update the RequiredMethodAsync count.");
var attribs = MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig;
bgen.AssertMethod ("NoAsyncInternalWrapperTests.MyFooDelegate_Extensions", "RequiredMethodAsync", attribs, "System.Threading.Tasks.Task", "NoAsyncInternalWrapperTests.IMyFooDelegate", "System.Int32");
@@ -644,13 +644,13 @@ public void ForcedType ()
});
});
- Assert.AreEqual (12, getINativeObjectCalls, "Preserve attribute count"); // If you modified code that generates PreserveAttributes please update the preserve count
+ Assert.That (getINativeObjectCalls, Is.EqualTo (12), "Preserve attribute count"); // If you modified code that generates PreserveAttributes please update the preserve count
}
[Test]
public void IsDirectBinding ()
{
- var bgen = BuildFile (Profile.iOS, "tests/is-direct-binding.cs");
+ var bgen = BuildFile (Profile.iOS, "is-direct-binding.cs");
var callsMethod = new Func ((method, name) => {
return method.Body.Instructions.Any ((ins) => {
@@ -658,7 +658,7 @@ public void IsDirectBinding ()
case Code.Call:
case Code.Calli:
case Code.Callvirt:
- var mr = ins.Operand as MethodReference;
+ var mr = (MethodReference) ins.Operand;
return mr.Name == name;
default:
return false;
@@ -705,7 +705,7 @@ public void Issue3875 (string file, string modelName)
{
var bgen = BuildFile (Profile.iOS, file);
var attrib = bgen.ApiAssembly.MainModule.GetType ("Issue3875", "AProtocol").CustomAttributes.Where ((v) => v.AttributeType.Name == "RegisterAttribute").First ();
- Assert.AreEqual (modelName, attrib.ConstructorArguments [0].Value, "Custom ObjC name");
+ Assert.That (attrib.ConstructorArguments [0].Value, Is.EqualTo (modelName), "Custom ObjC name");
}
[Test]
@@ -746,13 +746,13 @@ public void GH5416_setter (Profile profile)
[Test]
public void RefOutParameters ()
{
- BuildFile (Profile.macOSMobile, true, "tests/ref-out-parameters.cs");
+ BuildFile (Profile.macOSMobile, true, "ref-out-parameters.cs");
}
[Test]
public void ReturnRelease ()
{
- BuildFile (Profile.iOS, "tests/return-release.cs");
+ BuildFile (Profile.iOS, "return-release.cs");
}
[Test]
@@ -764,24 +764,24 @@ public void ReturnRelease ()
[Test]
public void IgnoreUnavailableProtocol ()
{
- var bgen = BuildFile (Profile.iOS, "tests/ignore-unavailable-protocol.cs");
+ var bgen = BuildFile (Profile.iOS, "ignore-unavailable-protocol.cs");
var myClass = bgen.ApiAssembly.MainModule.GetType ("NS", "MyClass");
var myProtocol = bgen.ApiAssembly.MainModule.GetType ("NS", "IMyProtocol");
var myClassInterfaces = myClass.Interfaces.Select (v => v.InterfaceType.Name).ToArray ();
Assert.That (myClassInterfaces, Does.Not.Contain ("IMyProtocol"), "IMyProtocol");
- Assert.IsNull (myProtocol, "MyProtocol null");
+ Assert.That (myProtocol, Is.Null, "MyProtocol null");
}
[Test]
public void VSTS970507 ()
{
- BuildFile (Profile.iOS, "tests/vsts-970507.cs");
+ BuildFile (Profile.iOS, "vsts-970507.cs");
}
[Test]
public void DiamondProtocol ()
{
- BuildFile (Profile.iOS, "tests/diamond-protocol.cs");
+ BuildFile (Profile.iOS, "diamond-protocol.cs");
}
[Test]
@@ -816,25 +816,25 @@ bool IsOptimizable (MethodDefinition method)
public void DisposeAttributeOptimizable ()
{
var profile = Profile.iOS;
- var bgen = BuildFile (profile, "tests/dispose-attribute.cs");
+ var bgen = BuildFile (profile, "dispose-attribute.cs");
// processing custom attributes (like its properties) will call Resolve so we must be able to find the platform assembly to run this test
- var resolver = bgen.ApiAssembly.MainModule.AssemblyResolver as BaseAssemblyResolver;
+ var resolver = (BaseAssemblyResolver) bgen.ApiAssembly.MainModule.AssemblyResolver;
resolver.AddSearchDirectory (Configuration.GetRefDirectory (profile.AsPlatform ()));
// [Dispose] is, by default, not optimizable
var with_dispose = bgen.ApiAssembly.MainModule.GetType ("NS", "WithDispose").Methods.First ((v) => v.Name == "Dispose");
- Assert.NotNull (with_dispose, "WithDispose");
+ Assert.That (with_dispose, Is.Not.Null, "WithDispose");
Assert.That (IsOptimizable (with_dispose), Is.False, "WithDispose/Optimizable");
// [Dispose] can opt-in being optimizable
var with_dispose_optin = bgen.ApiAssembly.MainModule.GetType ("NS", "WithDisposeOptInOptimizable").Methods.First ((v) => v.Name == "Dispose");
- Assert.NotNull (with_dispose_optin, "WithDisposeOptInOptimizable");
+ Assert.That (with_dispose_optin, Is.Not.Null, "WithDisposeOptInOptimizable");
Assert.That (IsOptimizable (with_dispose_optin), Is.True, "WithDisposeOptInOptimizable/Optimizable");
// Without a [Dispose] attribute the generated method is optimizable
var without_dispose = bgen.ApiAssembly.MainModule.GetType ("NS", "WithoutDispose").Methods.First ((v) => v.Name == "Dispose");
- Assert.NotNull (without_dispose, "WitoutDispose");
+ Assert.That (without_dispose, Is.Not.Null, "WitoutDispose");
Assert.That (IsOptimizable (without_dispose), Is.True, "WitoutDispose/Optimizable");
}
@@ -842,15 +842,15 @@ public void DisposeAttributeOptimizable ()
public void SnippetAttributesOptimizable ()
{
var profile = Profile.iOS;
- var bgen = BuildFile (profile, "tests/snippet-attributes.cs");
+ var bgen = BuildFile (profile, "snippet-attributes.cs");
// processing custom attributes (like its properties) will call Resolve so we must be able to find the platform assembly to run this test
- var resolver = bgen.ApiAssembly.MainModule.AssemblyResolver as BaseAssemblyResolver;
+ var resolver = (BaseAssemblyResolver) bgen.ApiAssembly.MainModule.AssemblyResolver;
resolver.AddSearchDirectory (Configuration.GetRefDirectory (profile.AsPlatform ()));
// [SnippetAttribute] subclasses are, by default, not optimizable
var not_opt = bgen.ApiAssembly.MainModule.GetType ("NS", "NotOptimizable");
- Assert.NotNull (not_opt, "NotOptimizable");
+ Assert.That (not_opt, Is.Not.Null, "NotOptimizable");
var pre_not_opt = not_opt.Methods.First ((v) => v.Name == "Pre");
Assert.That (IsOptimizable (pre_not_opt), Is.False, "NotOptimizable/Pre");
var prologue_not_opt = not_opt.Methods.First ((v) => v.Name == "Prologue");
@@ -860,7 +860,7 @@ public void SnippetAttributesOptimizable ()
// [SnippetAttribute] subclasses can opt-in being optimizable
var optin_opt = bgen.ApiAssembly.MainModule.GetType ("NS", "OptInOptimizable");
- Assert.NotNull (optin_opt, "OptInOptimizable");
+ Assert.That (optin_opt, Is.Not.Null, "OptInOptimizable");
var pre_optin_opt = optin_opt.Methods.First ((v) => v.Name == "Pre");
Assert.That (IsOptimizable (pre_optin_opt), Is.True, "OptInOptimizable/Pre");
var prologue_optin_opt = optin_opt.Methods.First ((v) => v.Name == "Prologue");
@@ -870,7 +870,7 @@ public void SnippetAttributesOptimizable ()
// Without a [SnippetAttribute] subclass attribute the generated method is optimizable
var nothing = bgen.ApiAssembly.MainModule.GetType ("NS", "NoSnippet").Methods.First ((v) => v.Name == "Nothing");
- Assert.NotNull (nothing, "NoSnippet");
+ Assert.That (nothing, Is.Not.Null, "NoSnippet");
Assert.That (IsOptimizable (nothing), Is.True, "Nothing/Optimizable");
}
@@ -883,8 +883,8 @@ public void NativeEnum (Profile profile)
bgen.Profile = profile;
bgen.ProcessEnums = true;
bgen.Defines = BGenTool.GetDefaultDefines (bgen.Profile);
- bgen.Sources = new string [] { Path.Combine (Configuration.SourceRoot, "tests", "generator", "tests", "nativeenum-extensions.cs") }.ToList ();
- bgen.ApiDefinitions = new string [] { Path.Combine (Configuration.SourceRoot, "tests", "generator", "tests", "nativeenum.cs") }.ToList ();
+ bgen.Sources = new string [] { Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", "nativeenum-extensions.cs") }.ToList ();
+ bgen.ApiDefinitions = new string [] { Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", "nativeenum.cs") }.ToList ();
bgen.CreateTemporaryBinding ();
bgen.AssertExecute ("build");
}
@@ -892,83 +892,83 @@ public void NativeEnum (Profile profile)
[Test]
public void DelegateWithINativeObjectReturnType ()
{
- var bgen = BuildFile (Profile.iOS, "tests/delegate-with-inativeobject-return-type.cs");
+ var bgen = BuildFile (Profile.iOS, "delegate-with-inativeobject-return-type.cs");
bgen.AssertExecute ("build");
// Assert that the return type from the delegate is IntPtr
var type = bgen.ApiAssembly.MainModule.GetType ("ObjCRuntime", "Trampolines").NestedTypes.First (v => v.Name == "DMyHandler");
- Assert.NotNull (type, "DMyHandler");
+ Assert.That (type, Is.Not.Null, "DMyHandler");
var method = type.Methods.First (v => v.Name == "Invoke");
- Assert.AreEqual ("ObjCRuntime.NativeHandle", method.ReturnType.FullName, "Return type");
+ Assert.That (method.ReturnType.FullName, Is.EqualTo ("ObjCRuntime.NativeHandle"), "Return type");
}
[Test]
public void ProtocolBindProperty ()
{
- var bgen = BuildFile (Profile.iOS, "tests/protocol-bind-property.cs");
+ var bgen = BuildFile (Profile.iOS, "protocol-bind-property.cs");
bgen.AssertExecute ("build");
// Assert that the return type from the delegate is IntPtr
var type = bgen.ApiAssembly.MainModule.GetType ("NS", "MyProtocol_Extensions");
- Assert.NotNull (type, "MyProtocol_Extensions");
+ Assert.That (type, Is.Not.Null, "MyProtocol_Extensions");
var method = type.Methods.First (v => v.Name == "GetOptionalProperty");
var ldstr = method.Body.Instructions.Single (v => v.OpCode == OpCodes.Ldstr);
- Assert.AreEqual ("isOptionalProperty", (string) ldstr.Operand, "isOptionalProperty");
+ Assert.That ((string) ldstr.Operand, Is.EqualTo ("isOptionalProperty"), "isOptionalProperty");
method = type.Methods.First (v => v.Name == "SetOptionalProperty");
ldstr = method.Body.Instructions.Single (v => v.OpCode == OpCodes.Ldstr);
- Assert.AreEqual ("setOptionalProperty:", (string) ldstr.Operand, "setOptionalProperty");
+ Assert.That ((string) ldstr.Operand, Is.EqualTo ("setOptionalProperty:"), "setOptionalProperty");
type = bgen.ApiAssembly.MainModule.GetType ("NS", "MyProtocolWrapper");
- Assert.NotNull (type, "MyProtocolWrapper");
+ Assert.That (type, Is.Not.Null, "MyProtocolWrapper");
method = type.Methods.First (v => v.Name == "get_AbstractProperty");
ldstr = method.Body.Instructions.Single (v => v.OpCode == OpCodes.Ldstr);
- Assert.AreEqual ("isAbstractProperty", (string) ldstr.Operand, "isAbstractProperty");
+ Assert.That ((string) ldstr.Operand, Is.EqualTo ("isAbstractProperty"), "isAbstractProperty");
method = type.Methods.First (v => v.Name == "set_AbstractProperty");
ldstr = method.Body.Instructions.Single (v => v.OpCode == OpCodes.Ldstr);
- Assert.AreEqual ("setAbstractProperty:", (string) ldstr.Operand, "setAbstractProperty");
+ Assert.That ((string) ldstr.Operand, Is.EqualTo ("setAbstractProperty:"), "setAbstractProperty");
}
[Test]
public void AbstractTypeTest ()
{
- var bgen = BuildFile (Profile.iOS, "tests/abstract-type.cs");
+ var bgen = BuildFile (Profile.iOS, "abstract-type.cs");
bgen.AssertExecute ("build");
// Assert that the return type from the delegate is IntPtr
var type = bgen.ApiAssembly.MainModule.GetType ("NS", "MyObject");
- Assert.NotNull (type, "MyObject");
- Assert.IsFalse (type.IsAbstract, "IsAbstract");
+ Assert.That (type, Is.Not.Null, "MyObject");
+ Assert.That (type.IsAbstract, Is.False, "IsAbstract");
var method = type.Methods.First (v => v.Name == ".ctor" && !v.HasParameters && !v.IsStatic);
- Assert.IsTrue (method.IsFamily, "IsProtected ctor");
+ Assert.That (method.IsFamily, Is.True, "IsProtected ctor");
method = type.Methods.First (v => v.Name == "AbstractMember" && !v.HasParameters && !v.IsStatic);
var throwInstruction = method.Body?.Instructions?.FirstOrDefault (v => v.OpCode == OpCodes.Throw);
- Assert.IsTrue (method.IsPublic, "IsPublic ctor");
- Assert.IsTrue (method.IsVirtual, "IsVirtual");
- Assert.IsFalse (method.IsAbstract, "IsAbstract");
- Assert.IsNotNull (throwInstruction, "Throw");
+ Assert.That (method.IsPublic, Is.True, "IsPublic ctor");
+ Assert.That (method.IsVirtual, Is.True, "IsVirtual");
+ Assert.That (method.IsAbstract, Is.False, "IsAbstract");
+ Assert.That (throwInstruction, Is.Not.Null, "Throw");
}
[Test]
[Ignore ("https://github.com/dotnet/roslyn/issues/61525")]
public void NativeIntDelegates ()
{
- var bgen = BuildFile (Profile.iOS, "tests/nint-delegates.cs");
+ var bgen = BuildFile (Profile.iOS, "nint-delegates.cs");
Func verifyDelegate = (typename) => {
// Assert that the return type from the delegate is IntPtr
var type = bgen.ApiAssembly.MainModule.GetType ("NS", typename);
- Assert.NotNull (type, typename);
+ Assert.That (type, Is.Not.Null, typename);
var method = type.Methods.First (m => m.Name == "Invoke");
- Assert.IsNotNull (method.MethodReturnType.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == "NativeIntegerAttribute"), "Return type for delegate " + typename);
+ Assert.That (method.MethodReturnType.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == "NativeIntegerAttribute"), Is.Not.Null, "Return type for delegate " + typename);
foreach (var p in method.Parameters) {
- Assert.IsNotNull (p.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == "NativeIntegerAttribute"), $"Parameter {p.Name}'s type for delegate " + typename);
+ Assert.That (p.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == "NativeIntegerAttribute"), Is.Not.Null, $"Parameter {p.Name}'s type for delegate " + typename);
}
return false;
@@ -983,7 +983,7 @@ public void NativeIntDelegates ()
[Test]
public void CSharp10Syntax ()
{
- BuildFile (Profile.iOS, "tests/csharp10syntax.cs");
+ BuildFile (Profile.iOS, "csharp10syntax.cs");
}
[Test]
@@ -994,7 +994,7 @@ public void AttributesFromInlinedProtocols (Profile profile)
var bgen = new BGenTool ();
bgen.Profile = profile;
- bgen.AddTestApiDefinition ("tests/attributes-from-inlined-protocols.cs");
+ bgen.AddTestApiDefinition ("attributes-from-inlined-protocols.cs");
bgen.CreateTemporaryBinding ();
bgen.AssertExecute ("build");
@@ -1056,12 +1056,14 @@ expectedAttributes [i] + "\n" +
[Test]
public void NFloatType ()
{
- var bgen = BuildFile (Profile.iOS, "tests/nfloat.cs");
+ var bgen = BuildFile (Profile.iOS, "nfloat.cs");
var messaging = bgen.ApiAssembly.MainModule.Types.FirstOrDefault (v => v.Name == "Messaging");
- Assert.IsNotNull (messaging, "Messaging");
+ Assert.That (messaging, Is.Not.Null, "Messaging");
+ if (messaging is null)
+ return;
var pinvoke = messaging.Methods.FirstOrDefault (v => v.Name == "xamarin_nfloat_objc_msgSend_exception");
- Assert.IsNotNull (pinvoke, "PInvoke");
+ Assert.That (pinvoke, Is.Not.Null, "PInvoke");
}
[Test]
@@ -1071,7 +1073,7 @@ public void NoAvailabilityForAccessors (Profile profile)
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
var bgen = new BGenTool ();
bgen.Profile = profile;
- bgen.AddTestApiDefinition ("tests/no-availability-for-accessors.cs");
+ bgen.AddTestApiDefinition ("no-availability-for-accessors.cs");
bgen.CreateTemporaryBinding ();
bgen.AssertExecute ("build");
@@ -1108,7 +1110,7 @@ public void NoAvailabilityForAccessors (Profile profile)
[Test]
public void GeneratedAttributeOnPropertyAccessors ()
{
- var bgen = BuildFile (Profile.MacCatalyst, "tests/generated-attribute-on-property-accessors.cs");
+ var bgen = BuildFile (Profile.MacCatalyst, "generated-attribute-on-property-accessors.cs");
var messaging = bgen.ApiAssembly.MainModule.Types.First (v => v.Name == "ISomething");
var property = messaging.Properties.First (v => v.Name == "IsLoadedInProcess");
@@ -1120,14 +1122,14 @@ public void GeneratedAttributeOnPropertyAccessors ()
[UnsupportedOSPlatform(""tvos"")]";
expectedPropertyAttributes = expectedPropertyAttributes.Replace ("\r", string.Empty);
- Assert.AreEqual (expectedPropertyAttributes, RenderSupportedOSPlatformAttributes (property), "Property attributes");
- Assert.AreEqual (string.Empty, RenderSupportedOSPlatformAttributes (getter), "Getter Attributes");
+ Assert.That (RenderSupportedOSPlatformAttributes (property), Is.EqualTo (expectedPropertyAttributes), "Property attributes");
+ Assert.That (RenderSupportedOSPlatformAttributes (getter), Is.EqualTo (string.Empty), "Getter Attributes");
}
[Test]
public void GeneratedAttributeOnPropertyAccessors2 ()
{
- var bgen = BuildFile (Profile.MacCatalyst, "tests/generated-attribute-on-property-accessors2.cs");
+ var bgen = BuildFile (Profile.MacCatalyst, "generated-attribute-on-property-accessors2.cs");
var messaging = bgen.ApiAssembly.MainModule.Types.First (v => v.Name == "ISomething");
var property = messaging.Properties.First (v => v.Name == "MicrophoneEnabled");
@@ -1148,16 +1150,16 @@ public void GeneratedAttributeOnPropertyAccessors2 ()
expectedPropertyAttributes = expectedPropertyAttributes.Replace ("\r", string.Empty);
expectedSetterAttributes = expectedSetterAttributes.Replace ("\r", string.Empty);
- Assert.AreEqual (expectedPropertyAttributes, RenderSupportedOSPlatformAttributes (property), "Property attributes");
- Assert.AreEqual (string.Empty, RenderSupportedOSPlatformAttributes (getter), "Getter Attributes");
- Assert.AreEqual (expectedSetterAttributes, RenderSupportedOSPlatformAttributes (setter), "Setter Attributes");
+ Assert.That (RenderSupportedOSPlatformAttributes (property), Is.EqualTo (expectedPropertyAttributes), "Property attributes");
+ Assert.That (RenderSupportedOSPlatformAttributes (getter), Is.EqualTo (string.Empty), "Getter Attributes");
+ Assert.That (RenderSupportedOSPlatformAttributes (setter), Is.EqualTo (expectedSetterAttributes), "Setter Attributes");
}
[Test]
[TestCase (Profile.iOS)]
public void NewerAvailabilityInInlinedProtocol (Profile profile)
{
- var bgen = BuildFile (profile, "tests/newer-availability-in-inlined-protocol.cs");
+ var bgen = BuildFile (profile, "newer-availability-in-inlined-protocol.cs");
var expectedMethods = new [] {
new {
@@ -1316,15 +1318,17 @@ public void NewerAvailabilityInInlinedProtocol (Profile profile)
foreach (var expected in expectedMethods) {
var type = bgen.ApiAssembly.MainModule.Types.FirstOrDefault (v => v.Name == expected.Type);
- Assert.IsNotNull (type, $"Type not found: {expected.Type}");
+ Assert.That (type, Is.Not.Null, $"Type not found: {expected.Type}");
if (type is null)
continue;
- Assert.AreEqual (expected.MethodCount, type.Methods.Count, $"Unexpected method count for {expected.Type}.\n\tActual methods:\n\t\t{string.Join ("\n\t\t", type.Methods.Select (v => v.FullName))}");
+ Assert.That (type.Methods.Count, Is.EqualTo (expected.MethodCount), $"Unexpected method count for {expected.Type}.\n\tActual methods:\n\t\t{string.Join ("\n\t\t", type.Methods.Select (v => v.FullName))}");
if (expected.MethodCount == 0)
continue;
foreach (var expectedMember in expected.Methods) {
var member = type.Methods.SingleOrDefault (v => v.Name == expectedMember.Method);
- Assert.IsNotNull (member, $"Method not found: {expectedMember.Method} in {type.FullName}");
+ Assert.That (member, Is.Not.Null, $"Method not found: {expectedMember.Method} in {type.FullName}");
+ if (member is null)
+ continue;
var renderedAttributes = RenderSupportedOSPlatformAttributes (member);
var expectedAttributes = expectedMember.Attributes.Replace ("\r", string.Empty);
if (renderedAttributes != expectedAttributes) {
@@ -1342,15 +1346,15 @@ public void NewerAvailabilityInInlinedProtocol (Profile profile)
foreach (var expected in expectedProperties) {
var type = bgen.ApiAssembly.MainModule.Types.FirstOrDefault (v => v.Name == expected.Type);
- Assert.IsNotNull (type, $"Type not found: {expected.Type}");
+ Assert.That (type, Is.Not.Null, $"Type not found: {expected.Type}");
if (type is null)
continue;
- Assert.AreEqual (expected.PropertyCount, type.Properties.Count, $"Unexpected property count for {expected.Type}.\n\tActual properties:\n\t\t{string.Join ("\n\t\t", type.Properties.Select (v => v.Name))}");
+ Assert.That (type.Properties.Count, Is.EqualTo (expected.PropertyCount), $"Unexpected property count for {expected.Type}.\n\tActual properties:\n\t\t{string.Join ("\n\t\t", type.Properties.Select (v => v.Name))}");
if (expected.PropertyCount == 0)
continue;
foreach (var expectedMember in expected.Properties) {
var member = type.Properties.SingleOrDefault (v => v.Name == expectedMember.Property);
- Assert.IsNotNull (member, $"Property not found: {expectedMember.Property} in {type.FullName}");
+ Assert.That (member, Is.Not.Null, $"Property not found: {expectedMember.Property} in {type.FullName}");
if (member is null)
continue;
var renderedAttributes = RenderSupportedOSPlatformAttributes (member);
@@ -1376,7 +1380,7 @@ public void NewerAvailabilityInInlinedProtocol (Profile profile)
[TestCase (Profile.iOS)]
public void ErrorDomain (Profile profile)
{
- BuildFile (profile, true, true, "tests/errordomain.cs");
+ BuildFile (profile, true, true, "errordomain.cs");
}
[Test]
@@ -1386,7 +1390,7 @@ public void ObsoletedOSPlatform (Profile profile)
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
var bgen = new BGenTool ();
bgen.Profile = profile;
- bgen.AddTestApiDefinition ("tests/obsoletedosplatform.cs");
+ bgen.AddTestApiDefinition ("obsoletedosplatform.cs");
bgen.CreateTemporaryBinding ();
bgen.AssertExecute ("build");
}
@@ -1394,7 +1398,7 @@ public void ObsoletedOSPlatform (Profile profile)
[Test]
public void InternalDelegate ()
{
- BuildFile (Profile.iOS, "tests/internal-delegate.cs");
+ BuildFile (Profile.iOS, "internal-delegate.cs");
}
[Test]
@@ -1404,10 +1408,10 @@ public void InternalDelegate ()
[TestCase (Profile.tvOS)]
public void XmlDocs (Profile profile)
{
- var bgen = BuildFile (profile, false, true, "tests/xmldocs.cs");
+ var bgen = BuildFile (profile, false, true, "xmldocs.cs");
Assert.That (bgen.XmlDocumentation, Does.Exist);
var contents = File.ReadAllText (bgen.XmlDocumentation);
- var expectedContentsPath = Path.Combine (Configuration.SourceRoot, "tests", "generator", $"ExpectedXmlDocs.{profile.AsPlatform ().AsString ()}.xml");
+ var expectedContentsPath = Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", $"ExpectedXmlDocs.{profile.AsPlatform ().AsString ()}.xml");
if (!File.Exists (expectedContentsPath))
File.WriteAllText (expectedContentsPath, string.Empty);
@@ -1420,9 +1424,9 @@ public void XmlDocs (Profile profile)
if (contents != expectedContents) {
if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("WRITE_KNOWN_FAILURES"))) {
File.WriteAllText (expectedContentsPath, contents);
- Assert.AreEqual (expectedContents, contents, $"Xml docs: The known failures have been updated in {expectedContentsPath}, so please commit the results. Re-running the test should now succeed.");
+ Assert.That (contents, Is.EqualTo (expectedContents), $"Xml docs: The known failures have been updated in {expectedContentsPath}, so please commit the results. Re-running the test should now succeed.");
} else {
- Assert.AreEqual (expectedContents, contents, $"Xml docs: If this is expected, set the WRITE_KNOWN_FAILURES=1 environment variable, run the test again, and commit the changes to the {expectedContentsPath} file.");
+ Assert.That (contents, Is.EqualTo (expectedContents), $"Xml docs: If this is expected, set the WRITE_KNOWN_FAILURES=1 environment variable, run the test again, and commit the changes to the {expectedContentsPath} file.");
}
}
}
@@ -1434,7 +1438,7 @@ public void XmlDocs (Profile profile)
[TestCase (Profile.tvOS)]
public void PreviewAPIs (Profile profile)
{
- var bgen = BuildFile (profile, false, true, "tests/preview.cs");
+ var bgen = BuildFile (profile, false, true, "preview.cs");
// Each Experimental attribute in the api definition has its own diagnostic ID (with an incremental number)
// Here we collect all diagnostic IDS for all the Experimental attributes in the compiled assembly,
@@ -1455,14 +1459,14 @@ public void PreviewAPIs (Profile profile)
[Test]
public void DelegateParameterAttributes ()
{
- BuildFile (Profile.iOS, "tests/delegate-parameter-attributes.cs");
+ BuildFile (Profile.iOS, "delegate-parameter-attributes.cs");
}
[Test]
public void Issue19612 ()
{
var profile = Profile.iOS;
- var filename = Path.Combine (Configuration.SourceRoot, "tests", "generator", "issue19612.cs");
+ var filename = Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", "issue19612.cs");
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
@@ -1485,7 +1489,7 @@ public void Issue19612 ()
cscArguments.Add ($"/r:{Configuration.GetBaseLibrary (tf)}");
BGenTool.AddPreviewNoWarn (cscArguments);
var rv = ExecutionHelper.Execute (cscExecutable, cscArguments);
- Assert.AreEqual (0, rv, "CSC exit code");
+ Assert.That (rv, Is.EqualTo (0), "CSC exit code");
var bgen = new BGenTool ();
bgen.Profile = profile;
@@ -1503,7 +1507,7 @@ public void Issue19612 ()
public void BackingFieldType (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, true, true, "tests/backingfieldtype.cs");
+ var bgen = BuildFile (profile, true, true, "backingfieldtype.cs");
const string nintName = "System.IntPtr";
const string nuintName = "System.UIntPtr";
@@ -1521,22 +1525,22 @@ public void BackingFieldType (Profile profile)
foreach (var tc in testCases) {
var getConstant = bgen.ApiAssembly.MainModule.GetType ("BackingField", $"{tc.BackingFieldType}FieldTypeExtensions").Methods.First ((v) => v.Name == "GetConstant");
- Assert.AreEqual (tc.NullableType, getConstant.ReturnType.FullName, $"{tc.BackingFieldType}: GetConstant return type");
+ Assert.That (getConstant.ReturnType.FullName, Is.EqualTo (tc.NullableType), $"{tc.BackingFieldType}: GetConstant return type");
var getValue = bgen.ApiAssembly.MainModule.GetType ("BackingField", $"{tc.BackingFieldType}FieldTypeExtensions").Methods.First ((v) => v.Name == "GetValue");
- Assert.AreEqual (tc.RenderedBackingFieldType, getValue.Parameters [0].ParameterType.FullName, $"{tc.BackingFieldType}: GetValue parameter type");
+ Assert.That (getValue.Parameters [0].ParameterType.FullName, Is.EqualTo (tc.RenderedBackingFieldType), $"{tc.BackingFieldType}: GetValue parameter type");
var toEnumArray = bgen.ApiAssembly.MainModule.GetType ("BackingField", $"{tc.BackingFieldType}FieldTypeExtensions").Methods.First ((v) => v.Name == "ToEnumArray");
- Assert.IsTrue (toEnumArray.ReturnType.IsArray, $"{tc.BackingFieldType} ToEnumArray return type IsArray");
- Assert.AreEqual ($"{tc.BackingFieldType}FieldType", toEnumArray.ReturnType.GetElementType ().Name, $"{tc.BackingFieldType} ToEnumArray return type");
- Assert.IsTrue (toEnumArray.Parameters [0].ParameterType.IsArray, $"{tc.BackingFieldType} ToEnumArray parameter type IsArray");
- Assert.AreEqual (tc.RenderedBackingFieldType, toEnumArray.Parameters [0].ParameterType.GetElementType ().FullName, $"{tc.BackingFieldType} ToEnumArray parameter type");
+ Assert.That (toEnumArray.ReturnType.IsArray, Is.True, $"{tc.BackingFieldType} ToEnumArray return type IsArray");
+ Assert.That (toEnumArray.ReturnType.GetElementType ().Name, Is.EqualTo ($"{tc.BackingFieldType}FieldType"), $"{tc.BackingFieldType} ToEnumArray return type");
+ Assert.That (toEnumArray.Parameters [0].ParameterType.IsArray, Is.True, $"{tc.BackingFieldType} ToEnumArray parameter type IsArray");
+ Assert.That (toEnumArray.Parameters [0].ParameterType.GetElementType ().FullName, Is.EqualTo (tc.RenderedBackingFieldType), $"{tc.BackingFieldType} ToEnumArray parameter type");
var toConstantArray = bgen.ApiAssembly.MainModule.GetType ("BackingField", $"{tc.BackingFieldType}FieldTypeExtensions").Methods.First ((v) => v.Name == "ToConstantArray");
- Assert.IsTrue (toConstantArray.ReturnType.IsArray, $"{tc.BackingFieldType} ToConstantArray return type IsArray");
- Assert.AreEqual (tc.SimplifiedNullableType, toConstantArray.ReturnType.GetElementType ().FullName, $"{tc.BackingFieldType} ToConstantArray return type");
- Assert.IsTrue (toConstantArray.Parameters [0].ParameterType.IsArray, $"{tc.BackingFieldType} ToConstantArray parameter type IsArray");
- Assert.AreEqual ($"{tc.BackingFieldType}FieldType", toConstantArray.Parameters [0].ParameterType.GetElementType ().Name, $"{tc.BackingFieldType} ToConstantArray parameter type");
+ Assert.That (toConstantArray.ReturnType.IsArray, Is.True, $"{tc.BackingFieldType} ToConstantArray return type IsArray");
+ Assert.That (toConstantArray.ReturnType.GetElementType ().FullName, Is.EqualTo (tc.SimplifiedNullableType), $"{tc.BackingFieldType} ToConstantArray return type");
+ Assert.That (toConstantArray.Parameters [0].ParameterType.IsArray, Is.True, $"{tc.BackingFieldType} ToConstantArray parameter type IsArray");
+ Assert.That (toConstantArray.Parameters [0].ParameterType.GetElementType ().Name, Is.EqualTo ($"{tc.BackingFieldType}FieldType"), $"{tc.BackingFieldType} ToConstantArray parameter type");
}
}
@@ -1545,7 +1549,7 @@ public void BackingFieldType (Profile profile)
public void UnderlyingFieldType (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- BuildFile (profile, true, true, "tests/underlyingfieldtype.cs");
+ BuildFile (profile, true, true, "underlyingfieldtype.cs");
}
[Test]
@@ -1556,7 +1560,7 @@ public void UnderlyingFieldType (Profile profile)
public void AvailabilityAttributes (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, "tests/availability-attributes.cs");
+ var bgen = BuildFile (profile, "availability-attributes.cs");
bgen.AssertNoWarnings ();
}
@@ -1565,7 +1569,7 @@ public void AvailabilityAttributes (Profile profile)
public void DelegatesWithNullableReturnType (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, "tests/delegate-nullable-return.cs");
+ var bgen = BuildFile (profile, "delegate-nullable-return.cs");
bgen.AssertNoWarnings ();
var delegateCallback = bgen.ApiAssembly.MainModule.GetType ("NS", "MyCallback").Methods.First ((v) => v.Name == "EndInvoke");
@@ -1577,13 +1581,13 @@ public void DelegatesWithNullableReturnType (Profile profile)
public void DelegatesWithPointerTypes (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, "tests/delegate-types.cs");
+ var bgen = BuildFile (profile, "delegate-types.cs");
bgen.AssertNoWarnings ();
var delegateCallback = bgen.ApiAssembly.MainModule.GetType ("NS", "MyCallback").Methods.First ((v) => v.Name == "EndInvoke");
- Assert.IsTrue (delegateCallback.MethodReturnType.ReturnType.IsPointer, "Pointer return type");
+ Assert.That (delegateCallback.MethodReturnType.ReturnType.IsPointer, Is.True, "Pointer return type");
foreach (var p in delegateCallback.Parameters.Where (v => v.Name != "result")) {
- Assert.IsTrue (p.ParameterType.IsPointer, $"Pointer parameter type: {p.Name}");
+ Assert.That (p.ParameterType.IsPointer, Is.True, $"Pointer parameter type: {p.Name}");
}
}
@@ -1592,7 +1596,7 @@ public void DelegatesWithPointerTypes (Profile profile)
public void ProtocolWithBaseTypeButNoModel (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, false, "tests/protocol-and-basetype-no-model.cs");
+ var bgen = BuildFile (profile, false, "protocol-and-basetype-no-model.cs");
bgen.AssertExecute ("build");
bgen.AssertWarning (1123, "The type Protocols.ProtocolWithBaseTypeButNoModel has a [Protocol] and a [BaseType] attribute, but no [Model] attribute. This is likely incorrect; either remove the [BaseType] attribute, or add a [Model] attribute.");
}
@@ -1602,7 +1606,7 @@ public void ProtocolWithBaseTypeButNoModel (Profile profile)
public void DesignatedInitializer (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, "tests/designated-initializer-issue-10106.cs");
+ var bgen = BuildFile (profile, "designated-initializer-issue-10106.cs");
bgen.AssertNoWarnings ();
}
@@ -1611,7 +1615,7 @@ public void DesignatedInitializer (Profile profile)
public void ReleaseAttribute (Profile profile)
{
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, "tests/release-attribute.cs");
+ var bgen = BuildFile (profile, "release-attribute.cs");
bgen.AssertNoWarnings ();
var passesOwnsEqualsTrue = new Func ((method) => {
@@ -1640,7 +1644,7 @@ public void ReleaseAttribute (Profile profile)
.Where (v => v.Name != "get_ClassHandle");
Assert.Multiple (() => {
foreach (var method in methods)
- Assert.True (passesOwnsEqualsTrue (method), method.Name);
+ Assert.That (passesOwnsEqualsTrue (method), Is.True, method.Name);
});
}
@@ -1650,7 +1654,7 @@ public void BothProtectedAndInternal (Profile profile)
{
// https://github.com/dotnet/macios/issues/6889
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
- var bgen = BuildFile (profile, "tests/both-protected-and-internal.cs");
+ var bgen = BuildFile (profile, "both-protected-and-internal.cs");
bgen.AssertNoWarnings ();
}
}
diff --git a/tests/generator/BGenTool.cs b/tests/bgen/BGenTool.cs
similarity index 97%
rename from tests/generator/BGenTool.cs
rename to tests/bgen/BGenTool.cs
index 20e666cce2ee..86ecf771286d 100644
--- a/tests/generator/BGenTool.cs
+++ b/tests/bgen/BGenTool.cs
@@ -46,12 +46,11 @@ class BGenTool : Tool {
public BGenTool ()
{
- EnvironmentVariables = new Dictionary ();
}
public void AddTestApiDefinition (string filename)
{
- ApiDefinitions.Add (Path.Combine (Configuration.SourceRoot, "tests", "generator", filename));
+ ApiDefinitions.Add (Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", filename));
}
public void AddExtraSourcesRelativeToGeneratorDirectory (string pathRelativeToGeneratorDirectory)
@@ -61,7 +60,7 @@ public void AddExtraSourcesRelativeToGeneratorDirectory (string pathRelativeToGe
public string GetFullPathRelativeToGeneratorDirectory (string pathRelativeToGeneratorDirectory)
{
- return Path.Combine (Configuration.SourceRoot, "tests", "generator", pathRelativeToGeneratorDirectory);
+ return Path.Combine (Configuration.SourceRoot, "tests", "bgen", "tests", pathRelativeToGeneratorDirectory);
}
public AssemblyDefinition ApiAssembly {
@@ -221,7 +220,7 @@ public void AssertExecute (string message)
public void AssertExecuteError (string message)
{
- Assert.AreNotEqual (0, Execute (), message);
+ Assert.That (Execute (), Is.Not.EqualTo (0), message);
}
int Execute ()
@@ -338,7 +337,7 @@ public void AssertType (string fullname, TypeAttributes? attributes = null, stri
return;
}
if (attributes is not null)
- Assert.AreEqual (attributes.Value, t.Attributes, $"Incorrect attributes for type {fullname}.");
+ Assert.That (t.Attributes, Is.EqualTo (attributes.Value), $"Incorrect attributes for type {fullname}.");
}
public void AssertMethod (string typename, string method, params string [] parameterTypes)
@@ -359,7 +358,7 @@ public void AssertMethod (string typename, string method, MethodAttributes? attr
return;
}
if (attributes.HasValue)
- Assert.AreEqual (attributes.Value, m.Attributes, "Attributes for {0}", m.FullName);
+ Assert.That (m.Attributes, Is.EqualTo (attributes.Value), $"Attributes for {m.FullName}");
}
public void AssertNoMethod (string typename, string method, string? returnType = null, params string [] parameterTypes)
diff --git a/tests/generator/CollectionsExtensionsTests.cs b/tests/bgen/CollectionsExtensionsTests.cs
similarity index 55%
rename from tests/generator/CollectionsExtensionsTests.cs
rename to tests/bgen/CollectionsExtensionsTests.cs
index b8ac7b9d0f41..b037b559d72a 100644
--- a/tests/generator/CollectionsExtensionsTests.cs
+++ b/tests/bgen/CollectionsExtensionsTests.cs
@@ -7,15 +7,15 @@ public class CollectionsExtensionsTests {
[Test]
public void Yield ()
- => Assert.AreEqual (1, "test".Yield ().Count ());
+ => Assert.That ("test".Yield ().Count (), Is.EqualTo (1));
[Test]
public void DropLast ()
{
var array = new [] { "first", "second", "last" };
var result = array.DropLast ();
- Assert.AreEqual (array.Length - 1, result.Length, "Result Length");
- Assert.False (result.Contains (array.Last ()), "Contains last item");
+ Assert.That (result.Length, Is.EqualTo (array.Length - 1), "Result Length");
+ Assert.That (result.Contains (array.Last ()), Is.False, "Contains last item");
}
}
diff --git a/tests/generator/ConstructorArgumentsTests.cs b/tests/bgen/ConstructorArgumentsTests.cs
similarity index 53%
rename from tests/generator/ConstructorArgumentsTests.cs
rename to tests/bgen/ConstructorArgumentsTests.cs
index 8c8c0b06b45f..e26518dea17c 100644
--- a/tests/generator/ConstructorArgumentsTests.cs
+++ b/tests/bgen/ConstructorArgumentsTests.cs
@@ -13,9 +13,9 @@ public void GetCtorValuesNullVersion ()
{
var args = new AttributeFactory.ConstructorArguments (PlatformName.iOS, "test");
var values = args.GetCtorValues ();
- Assert.AreEqual (2, values.Length, "Length");
- Assert.AreEqual ((byte) PlatformName.iOS, values [0], "Platform");
- Assert.AreEqual ("test", values [1], "Message");
+ Assert.That (values.Length, Is.EqualTo (2), "Length");
+ Assert.That (values [0], Is.EqualTo ((byte) PlatformName.iOS), "Platform");
+ Assert.That (values [1], Is.EqualTo ("test"), "Message");
}
[Test]
@@ -23,11 +23,11 @@ public void GetCtorValuesNullBuild ()
{
var args = new AttributeFactory.ConstructorArguments (PlatformName.iOS, 13, 0, "test");
var values = args.GetCtorValues ();
- Assert.AreEqual (4, values.Length, "Length");
- Assert.AreEqual ((byte) PlatformName.iOS, values [0], "Platform");
- Assert.AreEqual (13, values [1], "Major");
- Assert.AreEqual (0, values [2], "Minor");
- Assert.AreEqual ("test", values [3], "Message");
+ Assert.That (values.Length, Is.EqualTo (4), "Length");
+ Assert.That (values [0], Is.EqualTo ((byte) PlatformName.iOS), "Platform");
+ Assert.That (values [1], Is.EqualTo (13), "Major");
+ Assert.That (values [2], Is.EqualTo (0), "Minor");
+ Assert.That (values [3], Is.EqualTo ("test"), "Message");
}
[Test]
@@ -35,12 +35,12 @@ public void GetCtorValuesFullVersion ()
{
var args = new AttributeFactory.ConstructorArguments (PlatformName.iOS, 13, 0, 1, "test");
var values = args.GetCtorValues ();
- Assert.AreEqual (5, values.Length, "Length");
- Assert.AreEqual ((byte) PlatformName.iOS, values [0], "Platform");
- Assert.AreEqual (13, values [1], "Major");
- Assert.AreEqual (0, values [2], "Minor");
- Assert.AreEqual (1, values [3], "Build");
- Assert.AreEqual ("test", values [4], "Message");
+ Assert.That (values.Length, Is.EqualTo (5), "Length");
+ Assert.That (values [0], Is.EqualTo ((byte) PlatformName.iOS), "Platform");
+ Assert.That (values [1], Is.EqualTo (13), "Major");
+ Assert.That (values [2], Is.EqualTo (0), "Minor");
+ Assert.That (values [3], Is.EqualTo (1), "Build");
+ Assert.That (values [4], Is.EqualTo ("test"), "Message");
}
[Test]
@@ -48,9 +48,9 @@ public void GetCtorTypesNullVersion ()
{
var args = new AttributeFactory.ConstructorArguments (PlatformName.iOS, "test");
var types = args.GetCtorTypes ();
- Assert.AreEqual (2, types.Length, "Length");
- Assert.AreEqual (typeof (PlatformName), types [0], "Platform");
- Assert.AreEqual (typeof (string), types [1], "Message");
+ Assert.That (types.Length, Is.EqualTo (2), "Length");
+ Assert.That (types [0], Is.EqualTo (typeof (PlatformName)), "Platform");
+ Assert.That (types [1], Is.EqualTo (typeof (string)), "Message");
}
[Test]
@@ -58,11 +58,11 @@ public void GetCtorTypesNullBuild ()
{
var args = new AttributeFactory.ConstructorArguments (PlatformName.iOS, 13, 0, "test");
var types = args.GetCtorTypes ();
- Assert.AreEqual (4, types.Length, "Length");
- Assert.AreEqual (typeof (PlatformName), types [0], "Platform");
- Assert.AreEqual (typeof (int), types [1], "Major");
- Assert.AreEqual (typeof (int), types [2], "Minor");
- Assert.AreEqual (typeof (string), types [3], "Message");
+ Assert.That (types.Length, Is.EqualTo (4), "Length");
+ Assert.That (types [0], Is.EqualTo (typeof (PlatformName)), "Platform");
+ Assert.That (types [1], Is.EqualTo (typeof (int)), "Major");
+ Assert.That (types [2], Is.EqualTo (typeof (int)), "Minor");
+ Assert.That (types [3], Is.EqualTo (typeof (string)), "Message");
}
[Test]
@@ -70,12 +70,12 @@ public void GetCtorTypesFullVersion ()
{
var args = new AttributeFactory.ConstructorArguments (PlatformName.iOS, 13, 0, 1, "test");
var types = args.GetCtorTypes ();
- Assert.AreEqual (5, types.Length, "Length");
- Assert.AreEqual (typeof (PlatformName), types [0], "Platform");
- Assert.AreEqual (typeof (int), types [1], "Major");
- Assert.AreEqual (typeof (int), types [2], "Minor");
- Assert.AreEqual (typeof (int), types [3], "Build");
- Assert.AreEqual (typeof (string), types [4], "Message");
+ Assert.That (types.Length, Is.EqualTo (5), "Length");
+ Assert.That (types [0], Is.EqualTo (typeof (PlatformName)), "Platform");
+ Assert.That (types [1], Is.EqualTo (typeof (int)), "Major");
+ Assert.That (types [2], Is.EqualTo (typeof (int)), "Minor");
+ Assert.That (types [3], Is.EqualTo (typeof (int)), "Build");
+ Assert.That (types [4], Is.EqualTo (typeof (string)), "Message");
}
class TryGetArgumentsData : IEnumerable {
@@ -103,14 +103,14 @@ public void TryGetCtorArguments (object [] arguments, PlatformName platformName,
{
var success = AttributeFactory.ConstructorArguments.TryGetCtorArguments (arguments, platformName,
out var actualValues, out var actualTypes);
- Assert.True (success, "success");
- Assert.AreEqual (expectedValues!.Length, actualValues!.Length, "Values Length");
+ Assert.That (success, Is.True, "success");
+ Assert.That (actualValues!.Length, Is.EqualTo (expectedValues!.Length), "Values Length");
for (int index = 0; index < expectedValues.Length; index++) {
- Assert.AreEqual (expectedValues [index], actualValues [index], $"Values [{index}]");
+ Assert.That (actualValues [index], Is.EqualTo (expectedValues [index]), $"Values [{index}]");
}
- Assert.AreEqual (expectedTypes!.Length, actualTypes!.Length, "Types Length");
+ Assert.That (actualTypes!.Length, Is.EqualTo (expectedTypes!.Length), "Types Length");
for (int index = 0; index < expectedTypes.Length; index++) {
- Assert.AreEqual (expectedTypes [index], actualTypes [index], $"Types [{index}]");
+ Assert.That (actualTypes [index], Is.EqualTo (expectedTypes [index]), $"Types [{index}]");
}
}
@@ -119,9 +119,9 @@ public void TryGetCtorArgumentsFail ()
{
var success = AttributeFactory.ConstructorArguments.TryGetCtorArguments (Array.Empty