1851 строка
73 KiB
C#
1851 строка
73 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using Xamarin.Tests;
|
|
using Xamarin.Utils;
|
|
using NUnit.Framework;
|
|
|
|
using MTouchLinker = Xamarin.Tests.LinkerOption;
|
|
using MTouchRegistrar = Xamarin.Tests.RegistrarOption;
|
|
|
|
namespace Xamarin
|
|
{
|
|
[TestFixture]
|
|
public class Registrar
|
|
{
|
|
enum R {
|
|
Static = 4,
|
|
Dynamic = 8,
|
|
}
|
|
|
|
[Test]
|
|
public void InvalidParameterTypes ()
|
|
{
|
|
var code = @"
|
|
using System;
|
|
using Foundation;
|
|
class Foo : NSObject {
|
|
[Export (""bar1:"")]
|
|
public void Bar1 (object[] arg)
|
|
{
|
|
}
|
|
|
|
[Export (""bar2:"")]
|
|
public void Bar2 (ref object arg)
|
|
{
|
|
}
|
|
|
|
[Export (""bar3:"")]
|
|
public void Bar3 (out object arg)
|
|
{
|
|
arg = null;
|
|
}
|
|
|
|
[Export (""bar4:"")]
|
|
public void Bar4 (object arg)
|
|
{
|
|
}
|
|
|
|
[Export (""bar5"")]
|
|
public object Bar5 ()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
[Export (""bar6:"")]
|
|
public void Bar6 (int? arg)
|
|
{
|
|
}
|
|
|
|
[Export (""bar7"")]
|
|
public int? Bar7 ()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
[Export (""bar8:"")]
|
|
public void Bar8 (ref int?[] arg)
|
|
{
|
|
}
|
|
|
|
[Export (""bar9:"")]
|
|
public static void Bar9 (Attribute attribute)
|
|
{
|
|
}
|
|
|
|
[Export (""bar10"")]
|
|
public object Bar10 { get; set; }
|
|
|
|
public object[] Bar11 {
|
|
[Export (""bar11Getter"")]
|
|
get { return null; }
|
|
[Export (""bar11Setter:"")]
|
|
set {}
|
|
}
|
|
}
|
|
class C { static void Main () {} }
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (code: code, extraArgs: new [] { "-debug" });
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertError (4138, "The registrar cannot marshal the property type 'System.Object' of the property 'Foo.Bar10'.", "testApp.cs", 54);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Object[]' of the parameter 'arg' in the method 'Foo.Bar1(System.Object[])'", "testApp.cs", 7);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Object&' of the parameter 'arg' in the method 'Foo.Bar2(System.Object&)'", "testApp.cs", 12);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Object&' of the parameter 'arg' in the method 'Foo.Bar3(System.Object&)'", "testApp.cs", 17);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Object' of the parameter 'arg' in the method 'Foo.Bar4(System.Object)'", "testApp.cs", 23);
|
|
mtouch.AssertError (4104, "The registrar cannot marshal the return value of type `System.Object` in the method `Foo.Bar5()`.", "testApp.cs", 28);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Nullable`1<System.Int32>' of the parameter 'arg' in the method 'Foo.Bar6(System.Nullable`1<System.Int32>)'", "testApp.cs", 34);
|
|
mtouch.AssertError (4104, "The registrar cannot marshal the return value of type `System.Nullable`1<System.Int32>` in the method `Foo.Bar7()`.", "testApp.cs", 39);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Nullable`1<System.Int32>[]&' of the parameter 'arg' in the method 'Foo.Bar8(System.Nullable`1<System.Int32>[]&)'", "testApp.cs", 45);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Attribute' of the parameter 'attribute' in the method 'Foo.Bar9(System.Attribute)'", "testApp.cs", 50);
|
|
mtouch.AssertError (4104, "The registrar cannot marshal the return value of type `System.Object[]` in the method `Foo.get_Bar11()`.", "testApp.cs", 58);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Object[]' of the parameter 'value' in the method 'Foo.set_Bar11(System.Object[])'", "testApp.cs", 60);
|
|
mtouch.AssertErrorCount (12);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4102 ()
|
|
{
|
|
var code = @"
|
|
class DateMembers : NSObject {
|
|
[Export (""F1:"")]
|
|
void F1 (DateTime a) {}
|
|
|
|
[Export (""F2"")]
|
|
DateTime F2 () { throw new Exception (); }
|
|
|
|
[Export (""F3:"")]
|
|
void F3 (ref DateTime d) {}
|
|
|
|
[Export (""F4"")]
|
|
DateTime F4 { get; set; }
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using System;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4138, "The registrar cannot marshal the property type 'System.DateTime' of the property 'DateMembers.F4'.", "testApp.cs", 14);
|
|
mtouch.AssertError (4102, "The registrar found an invalid type `System.DateTime` in signature for method `DateMembers.F1`. Use `Foundation.NSDate` instead.", "testApp.cs", 5);
|
|
mtouch.AssertError (4102, "The registrar found an invalid type `System.DateTime` in signature for method `DateMembers.F2`. Use `Foundation.NSDate` instead.", "testApp.cs", 8);
|
|
mtouch.AssertError (4102, "The registrar found an invalid type `System.DateTime` in signature for method `DateMembers.F3`. Use `Foundation.NSDate` instead.", "testApp.cs", 11);
|
|
mtouch.AssertErrorCount (4);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4111 ()
|
|
{
|
|
var code = @"
|
|
class DateMembers : NSObject {
|
|
[Export (""F1:"")]
|
|
void F1 (int[] a) {}
|
|
|
|
[Export (""F2"")]
|
|
int[] F2 () { throw new Exception (); }
|
|
|
|
[Export (""F3:"")]
|
|
void F3 (ref int[] d) {}
|
|
|
|
[Export (""F4"")]
|
|
int[] F4 { get; set; }
|
|
|
|
[Export (""F5:"")]
|
|
void F5 (out int[] d) { throw new Exception (); }
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using System;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `System.Int32[]' in method `DateMembers.F1`.", "testApp.cs", 5);
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `System.Int32[]' in method `DateMembers.F2`.", "testApp.cs", 8);
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `System.Int32[]' in method `DateMembers.F3`.", "testApp.cs", 11);
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `System.Int32[]' in method `DateMembers.get_F4`.", "testApp.cs", 14);
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `System.Int32[]' in method `DateMembers.set_F4`.", "testApp.cs", 14);
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `System.Int32[]' in method `DateMembers.F5`.", "testApp.cs", 17);
|
|
mtouch.AssertErrorCount (6);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4117 ()
|
|
{
|
|
var code = @"
|
|
class ArgCount : NSObject {
|
|
[Export (""F1"")]
|
|
void F1 (int a) {}
|
|
|
|
[Export (""F2:"")]
|
|
void F2 () {}
|
|
|
|
[Export (""F3"", IsVariadic = true)]
|
|
void F3 () {}
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4117, "The registrar found a signature mismatch in the method 'ArgCount.F1' - the selector 'F1' indicates the method takes 0 parameters, while the managed method has 1 parameters.", "testApp.cs", 5);
|
|
mtouch.AssertError (4117, "The registrar found a signature mismatch in the method 'ArgCount.F2' - the selector 'F2:' indicates the method takes 1 parameters, while the managed method has 0 parameters.", "testApp.cs", 8);
|
|
mtouch.AssertError (4140, "The registrar found a signature mismatch in the method 'ArgCount.F3' - the selector 'F3' indicates the variadic method takes 1 parameters, while the managed method has 0 parameters.", "testApp.cs", 11);
|
|
mtouch.AssertErrorCount (3);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4123 ()
|
|
{
|
|
var code = @"
|
|
class ArgCount : NSObject {
|
|
[Export (""F2"", IsVariadic = true)]
|
|
void F2 (System.IntPtr foo) {}
|
|
|
|
[Export (""F3"", IsVariadic = true)]
|
|
void F3 (int foo) {}
|
|
|
|
[Export (""F4:"", IsVariadic = true)]
|
|
void F4 (int foo, IntPtr bar) {}
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using System;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4123, "The type of the variadic parameter in the variadic function 'F3(System.Int32)' must be System.IntPtr.", "testApp.cs", 8);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4127 ()
|
|
{
|
|
var str1 = @"
|
|
[Protocol]
|
|
interface IFoo1 {
|
|
[Preserve (Conditional = true)]
|
|
[Export (""foo"")]
|
|
void GetFoo ();
|
|
}
|
|
|
|
[Protocol]
|
|
interface IFoo2 {
|
|
[Preserve (Conditional = true)]
|
|
[Export (""foo"")]
|
|
void GetFoo ();
|
|
}
|
|
|
|
[Preserve ()]
|
|
class MyObjectErr : NSObject, IFoo1, IFoo2
|
|
{
|
|
public void GetFoo ()
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: str1, usings: "using Foundation; using System;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4127, "Cannot register more than one interface method for the method 'MyObjectErr.GetFoo'.");
|
|
mtouch.AssertError (4137, "The method 'MyObjectErr.GetFoo' is implementing 'IFoo1.GetFoo'.");
|
|
mtouch.AssertError (4137, "The method 'MyObjectErr.GetFoo' is implementing 'IFoo2.GetFoo'.");
|
|
mtouch.AssertErrorCount (3);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4134 ()
|
|
{
|
|
var xcodeRoot = Configuration.xcode83_root;
|
|
if (!Directory.Exists (xcodeRoot))
|
|
Assert.Ignore ("Xcode 8 ({0}) is required for this test.", xcodeRoot);
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.SdkRoot = xcodeRoot;
|
|
mtouch.Sdk = "10.3";
|
|
|
|
// Create a source file that references most platform types.
|
|
var sb = new StringBuilder ();
|
|
var xidll = Mono.Cecil.AssemblyDefinition.ReadAssembly (MTouch.GetBaseLibrary (mtouch.Profile));
|
|
var xitypes = xidll.MainModule.Types
|
|
.Where ((v) => v.IsPublic && !v.Name.Contains ("`"))
|
|
.Where ((v) => {
|
|
switch (v.Namespace) {
|
|
case "CoreML":
|
|
case "CoreImage":
|
|
// These run into other registrar errors, so just skip them
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
});
|
|
sb.AppendLine ("[Preserve (AllMembers = true)] class preserveTypes { static void M () {");
|
|
foreach (var t in xitypes)
|
|
sb.AppendLine ($"System.Console.WriteLine (typeof ({t.Namespace}.{t.Name}));");
|
|
sb.AppendLine ("}}");
|
|
|
|
mtouch.CreateTemporaryApp (extraCode: sb.ToString (), usings: "using System; using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.LinkSdk;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildDev);
|
|
var invalidFrameworks = new [] {
|
|
new { Framework = "IdentityLookup", Version = "11.0" },
|
|
new { Framework = "FileProviderUI", Version = "11.0" },
|
|
new { Framework = "FileProvider", Version = "11.0" },
|
|
new { Framework = "DeviceCheck", Version = "11.0" },
|
|
new { Framework = "CoreNFC", Version = "11.0" },
|
|
new { Framework = "Vision", Version = "11.0" },
|
|
new { Framework = "PDFKit", Version = "11.0" },
|
|
new { Framework = "IOSurface", Version = "11.0" },
|
|
new { Framework = "ARKit", Version = "11.0" },
|
|
new { Framework = "BusinessChat", Version = "11.3" },
|
|
new { Framework = "ClassKit", Version = "11.4" },
|
|
new { Framework = "AuthenticationServices", Version = "12.0" },
|
|
new { Framework = "CarPlay", Version = "12.0" },
|
|
new { Framework = "IdentityLookupUI", Version = "12.0" },
|
|
new { Framework = "NaturalLanguage", Version = "12.0" },
|
|
};
|
|
foreach (var framework in invalidFrameworks)
|
|
mtouch.AssertError (4134, $"Your application is using the '{framework.Framework}' framework, which isn't included in the iOS SDK you're using to build your app (this framework was introduced in iOS {framework.Version}, while you're building with the iOS {mtouch.Sdk} SDK.) Please select a newer SDK in your app's iOS Build options.");
|
|
mtouch.AssertErrorCount (invalidFrameworks.Length);
|
|
mtouch.AssertWarningPattern (79, $"The recommended Xcode version for Xamarin.iOS .* is Xcode .* or later. The current Xcode version .found in /Applications/Xcode83.app/Contents/Developer. is .*.");
|
|
mtouch.AssertWarningCount (1);
|
|
|
|
mtouch.AssertExecute (MTouchAction.BuildSim);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4135 ()
|
|
{
|
|
var code = @"
|
|
class C : NSObject {
|
|
[Export (null)]
|
|
public void Bar () {}
|
|
|
|
[Export ("""")]
|
|
public void Zap () {}
|
|
}";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4135, "The member 'C.Bar' has an Export attribute without a selector. A selector is required.", "testApp.cs", 5);
|
|
mtouch.AssertError (4135, "The member 'C.Zap' has an Export attribute without a selector. A selector is required.", "testApp.cs", 8);
|
|
mtouch.AssertErrorCount (2);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4138 ()
|
|
{
|
|
var code = @"
|
|
class C : NSObject {
|
|
[Export (""foo"")]
|
|
object Foo { get { return null; } }
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4138, "The registrar cannot marshal the property type 'System.Object' of the property 'C.Foo'.", "testApp.cs", 5);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4139 ()
|
|
{
|
|
var code = @"
|
|
class C : NSObject {
|
|
[Connect]
|
|
object P1 { get { return null; } }
|
|
|
|
[Connect]
|
|
int P2 { get { return 0; } }
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4139, "The registrar cannot marshal the property type 'System.Object' of the property 'C.P1'. Properties with the [Connect] attribute must have a property type of NSObject (or a subclass of NSObject).", "testApp.cs", 5);
|
|
mtouch.AssertError (4139, "The registrar cannot marshal the property type 'System.Int32' of the property 'C.P2'. Properties with the [Connect] attribute must have a property type of NSObject (or a subclass of NSObject).", "testApp.cs", 8);
|
|
mtouch.AssertErrorCount (2);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4141 ()
|
|
{
|
|
var code = @"
|
|
class C : NSObject {
|
|
[Export (""retain"")]
|
|
new void Retain () {}
|
|
|
|
[Export (""release"")]
|
|
new void Release () {}
|
|
|
|
[Export (""dealloc"")]
|
|
new void Dealloc () {}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4141, "Cannot register the selector 'retain' on the member 'C.Retain' because Xamarin.iOS implicitly registers this selector.", "testApp.cs", 5);
|
|
mtouch.AssertError (4141, "Cannot register the selector 'release' on the member 'C.Release' because Xamarin.iOS implicitly registers this selector.", "testApp.cs", 8);
|
|
mtouch.AssertErrorCount (2);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4145 ()
|
|
{
|
|
var code = @"
|
|
[Native]
|
|
public enum Foo : int
|
|
{
|
|
}
|
|
class C : NSObject {
|
|
[Export (""nativeEnum1:"")]
|
|
void NativeEnum1 (Foo foo) {}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4145, "Invalid enum 'Foo': enums with the [Native] attribute must have a underlying enum type of either 'long' or 'ulong'.");
|
|
mtouch.AssertErrorCount (5); // The same MT4145 is printed 5 times
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4146 ()
|
|
{
|
|
var code = @"
|
|
[Register ("" C"")]
|
|
class C : NSObject {
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecute ();
|
|
mtouch.AssertWarning (4146, "The Name parameter of the Registrar attribute on the class 'C' (' C') contains an invalid character: ' ' (0x20).");
|
|
mtouch.AssertErrorCount (0);
|
|
mtouch.AssertWarningCount (1);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4146_b ()
|
|
{
|
|
var code = @"
|
|
[Register (""A C"")]
|
|
class C : NSObject {
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4146, "The Name parameter of the Registrar attribute on the class 'C' ('A C') contains an invalid character: ' ' (0x20).");
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
[Test]
|
|
public void MT4148 ()
|
|
{
|
|
var code = @"
|
|
[Protocol]
|
|
interface IProtocol<T> {
|
|
}
|
|
[Protocol]
|
|
interface IProtocol2 {
|
|
[Export (""M"")]
|
|
void M<T> ();
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4148, "The registrar found a generic protocol: 'IProtocol`1'. Exporting generic protocols is not supported.");
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'IProtocol2.M()'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes");
|
|
mtouch.AssertErrorCount (2);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4149 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (NSString))]
|
|
public static class Category
|
|
{
|
|
[Export (""foo"")]
|
|
public static void Foo (this int bar) {}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4149, "Cannot register the extension method 'Category.Foo' because the type of the first parameter ('System.Int32') does not match the category type ('Foundation.NSString').", "testApp.cs", 7);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4150 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (string))]
|
|
public static class Category
|
|
{
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4150, "Cannot register the type 'Category' because the category type 'System.String' in its Category attribute does not inherit from NSObject.");
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4151 ()
|
|
{
|
|
var code = @"
|
|
[Category (null)]
|
|
public static class Category
|
|
{
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4151, "Cannot register the type 'Category' because the Type property in its Category attribute isn't set.");
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4152 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (NSString))]
|
|
public class Category1 : NSObject
|
|
{
|
|
}
|
|
[Category (typeof (NSString))]
|
|
public class Category2 : INativeObject
|
|
{
|
|
public IntPtr Handle { get { return IntPtr.Zero; } }
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using System; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4152, "Cannot register the type 'Category1' as a category because it implements INativeObject or subclasses NSObject.");
|
|
mtouch.AssertError (4152, "Cannot register the type 'Category2' as a category because it implements INativeObject or subclasses NSObject.");
|
|
mtouch.AssertErrorCount (2);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4153 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (NSString))]
|
|
public class Category<T>
|
|
{
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4153, "Cannot register the type 'Category`1' as a category because it's generic.");
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4154 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (NSString))]
|
|
public class Category
|
|
{
|
|
[Export (""foo"")]
|
|
public static void Foo<T> () {}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4154, "Cannot register the method 'Category.Foo' as a category method because it's generic.", "testApp.cs", 7);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
// MT4155 only happens with the dynamic registrar
|
|
|
|
[Test]
|
|
public void MT4156 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (NSString), Name = ""C"")]
|
|
public class Category1
|
|
{
|
|
}
|
|
[Category (typeof (NSString), Name = ""C"")]
|
|
public class Category2
|
|
{
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4156, "Cannot register two categories ('Category2, testApp' and 'Category1, testApp') with the same native name ('C')");
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
// MT4157 Can't be produced using C#, since it requires using [Extension] manually:
|
|
// Test.cs(14,35): error CS1112: Do not use `System.Runtime.CompilerServices.ExtensionAttribute' directly. Use parameter modifier `this' instead
|
|
|
|
[Test]
|
|
public void MT4158 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (NSString))]
|
|
public class Category
|
|
{
|
|
[Export (""init"")]
|
|
public Category () {}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4158, "Cannot register the constructor Category..ctor() in the category Category because constructors in categories are not supported.", "testApp.cs", 7);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4159 ()
|
|
{
|
|
var code = @"
|
|
[Category (typeof (NSString))]
|
|
public class Category
|
|
{
|
|
[Export (""foo"")]
|
|
public void Foo () {}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4159, "Cannot register the method 'Category.Foo' as a category method because category methods must be static.", "testApp.cs", 7);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
// This list is duplicated in src/ObjCRuntime/Registrar.cs
|
|
static readonly char[] invalidSelectorCharacters = { ' ', '\t', '?', '\\', '!', '|', '@', '"', '\'', '%', '&', '/', '(', ')', '=', '^', '[', ']', '{', '}', ',', '.', ';', '-', '\n', '<', '>' };
|
|
|
|
[Test]
|
|
public void MT4160 ()
|
|
{
|
|
// newline is invalid, but it messes up the error message and testing is just annoying, so skip it.
|
|
var testInvalidCharacters = invalidSelectorCharacters.Where ((v) => v != '\n').ToArray ();
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var sb = new StringBuilder ();
|
|
sb.AppendLine ("public class TestInvalidChar : Foundation.NSObject {");
|
|
for (int i = 0; i < testInvalidCharacters.Length; i++) {
|
|
var c = testInvalidCharacters [i];
|
|
var str = c.ToString ();
|
|
switch (c) {
|
|
case '"':
|
|
str = "\"\"";
|
|
break;
|
|
}
|
|
sb.AppendLine ($"\t[Foundation.Export (@\"X{str}\")]");
|
|
sb.AppendLine ($"\tpublic void X{i} () {{}}");
|
|
}
|
|
sb.AppendLine ("}");
|
|
mtouch.CreateTemporaryApp (extraCode: sb.ToString (), extraArgs: new [] { "-debug" });
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
for (int i = 0; i < testInvalidCharacters.Length; i++) {
|
|
var c = testInvalidCharacters [i];
|
|
mtouch.AssertError (4160, $"Invalid character '{c}' (0x{((int)c).ToString ("x")}) found in selector 'X{c}' for 'TestInvalidChar.X{i}()'", "testApp.cs", 3 + i * 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4161 ()
|
|
{
|
|
var code = @"
|
|
public class TestInvalidChar : NSObject
|
|
{
|
|
[Export (""foo1"")]
|
|
public FooA Foo1 () { return new FooA (); }
|
|
|
|
[Export (""foo2:"")]
|
|
public void Foo2 (FooB foo) { }
|
|
|
|
[Export (""foo3:"")]
|
|
public void Foo3 (ref FooC foo) { }
|
|
|
|
[Export (""foo4:"")]
|
|
public void Foo4 (out FooD foo) { foo = new FooD (); }
|
|
|
|
[Export (""foo5:"")]
|
|
public void Foo5 (FooE[] foo) { }
|
|
|
|
[Export (""foo6"")]
|
|
public FooF[] Foo6 () { return null; }
|
|
}
|
|
public struct FooA { public NSObject Obj; }
|
|
public struct FooB { public NSObject Obj; }
|
|
public struct FooC { public NSObject Obj; }
|
|
public struct FooD { public NSObject Obj; }
|
|
public struct FooE { public NSObject Obj; }
|
|
public struct FooF { public NSObject Obj; }
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4161, "The registrar found an unsupported structure 'FooA': All fields in a structure must also be structures (field 'Obj' with type 'Foundation.NSObject' is not a structure).", "testApp.cs", 6);
|
|
mtouch.AssertError (4161, "The registrar found an unsupported structure 'FooB': All fields in a structure must also be structures (field 'Obj' with type 'Foundation.NSObject' is not a structure).", "testApp.cs", 9);
|
|
mtouch.AssertError (4161, "The registrar found an unsupported structure 'FooC': All fields in a structure must also be structures (field 'Obj' with type 'Foundation.NSObject' is not a structure).", "testApp.cs", 12);
|
|
mtouch.AssertError (4161, "The registrar found an unsupported structure 'FooD': All fields in a structure must also be structures (field 'Obj' with type 'Foundation.NSObject' is not a structure).", "testApp.cs", 15);
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `FooE[]' in method `TestInvalidChar.Foo5`.", "testApp.cs", 18);
|
|
mtouch.AssertError (4111, "The registrar cannot build a signature for type `FooF[]' in method `TestInvalidChar.Foo6`.", "testApp.cs", 21);
|
|
mtouch.AssertErrorCount (6);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
|
|
[Test]
|
|
[TestCase (Profile.iOS, "iOS", MTouchLinker.DontLink)]
|
|
[TestCase (Profile.tvOS, "tvOS", MTouchLinker.DontLink)]
|
|
[TestCase (Profile.iOS, "iOS", MTouchLinker.LinkAll)]
|
|
//[TestCase (Profile.WatchOS, "watchOS")] // MT0077 interferes
|
|
public void MT4162 (Profile profile, string name, MTouchLinker linker)
|
|
{
|
|
var code = @"
|
|
[Introduced (PlatformName.iOS, 99, 0, 0, PlatformArchitecture.All, ""use Z instead"")]
|
|
[Introduced (PlatformName.TvOS, 99, 0, 0, PlatformArchitecture.All, ""use Z instead"")]
|
|
[Introduced (PlatformName.WatchOS, 99, 0, 0, PlatformArchitecture.All, ""use Z instead"")]
|
|
[Introduced (PlatformName.iOS, 89, 0, 0, PlatformArchitecture.All)]
|
|
[Introduced (PlatformName.TvOS, 89, 0, 0, PlatformArchitecture.All)]
|
|
[Introduced (PlatformName.WatchOS, 89, 0, 0, PlatformArchitecture.All)]
|
|
[Register (IsWrapper = true)]
|
|
class FutureType : NSObject
|
|
{
|
|
public FutureType () {}
|
|
}
|
|
|
|
class CurrentType : FutureType
|
|
{
|
|
[Export (""foo:"")]
|
|
public void Foo (FutureType ft)
|
|
{
|
|
}
|
|
|
|
[Export (""bar"")]
|
|
public FutureType Bar ()
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[Export (""zap"")]
|
|
public FutureType Zap { get; set; }
|
|
|
|
// This is actually working now, but only because we erase the generic argument when converting to ObjC.
|
|
[Export (""zaps"")]
|
|
public NSSet<FutureType> Zaps { get; set; }
|
|
}
|
|
|
|
[Protocol (Name = ""FutureProtocol"")]
|
|
[ProtocolMember (IsRequired = false, IsProperty = true, IsStatic = false, Name = ""FutureProperty"", Selector = ""futureProperty"", PropertyType = typeof (FutureEnum), GetterSelector = ""futureProperty"", SetterSelector = ""setFutureProperty:"", ArgumentSemantic = ArgumentSemantic.UnsafeUnretained)]
|
|
[ProtocolMember (IsRequired = true, IsProperty = false, IsStatic = false, Name = ""FutureMethod"", Selector = ""futureMethod"", ReturnType = typeof (FutureEnum), ParameterType = new Type [] { typeof (FutureEnum) }, ParameterByRef = new bool [] { false })]
|
|
public interface IFutureProtocol : INativeObject, IDisposable
|
|
{
|
|
}
|
|
|
|
[Introduced (PlatformName.iOS, 99, 0, 0, PlatformArchitecture.All)]
|
|
[Introduced (PlatformName.TvOS, 99, 0, 0, PlatformArchitecture.All)]
|
|
[Introduced (PlatformName.WatchOS, 99, 0, 0, PlatformArchitecture.All)]
|
|
public enum FutureEnum {
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.Profile = profile;
|
|
mtouch.Linker = linker;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: code, extraArgs: new [] { "-debug" }, usings: "using System;\nusing Foundation;\nusing ObjCRuntime;\n");
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as a base type of CurrentType) is not available in {name} .* (it was introduced in {name} 99.0.0): 'use Z instead'. Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", custom_pattern_syntax: true);
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as a base type of CurrentType) is not available in {name} .* (it was introduced in {name} 89.0.0). Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", custom_pattern_syntax: true);
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as the property type of CurrentType.Zap) is not available in {name} .* (it was introduced in {name} 99.0.0): 'use Z instead'. Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", "testApp.cs", custom_pattern_syntax: true);
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as the property type of CurrentType.Zap) is not available in {name} .* (it was introduced in {name} 89.0.0). Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", "testApp.cs", custom_pattern_syntax: true);
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as a parameter in CurrentType.Foo) is not available in {name} .* (it was introduced in {name} 99.0.0): 'use Z instead'. Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", "testApp.cs", custom_pattern_syntax: true);
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as a parameter in CurrentType.Foo) is not available in {name} .* (it was introduced in {name} 89.0.0). Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", "testApp.cs", custom_pattern_syntax: true);
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as a return type in CurrentType.Bar) is not available in {name} .* (it was introduced in {name} 99.0.0): 'use Z instead'. Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", "testApp.cs", custom_pattern_syntax: true);
|
|
mtouch.AssertErrorPattern (4162, $"The type 'FutureType' (used as a return type in CurrentType.Bar) is not available in {name} .* (it was introduced in {name} 89.0.0). Please build with a newer {name} SDK (usually done by using the most recent version of Xcode).", "testApp.cs", custom_pattern_syntax: true);
|
|
}
|
|
}
|
|
|
|
static string [] objective_c_keywords = new string [] {
|
|
"auto",
|
|
"break",
|
|
"case", "char", "const", "continue",
|
|
"default", "do", "double",
|
|
"else", "enum", "export", "extern",
|
|
"float", "for",
|
|
"goto",
|
|
"if", "inline", "int",
|
|
"long",
|
|
"register", "return",
|
|
"short", "signed", "sizeof", "static", "struct", "switch",
|
|
"template", "typedef", "union",
|
|
"unsigned",
|
|
"void", "volatile",
|
|
"while",
|
|
"_Bool",
|
|
"_Complex",
|
|
};
|
|
|
|
[Test]
|
|
public void MT4164 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var sb = new StringBuilder ();
|
|
sb.AppendLine ("class FutureType : Foundation.NSObject {");
|
|
foreach (var kw in objective_c_keywords)
|
|
sb.AppendLine ($"[Foundation.Export (\"{kw}\")] string X{kw} {{ get; set; }}");
|
|
sb.AppendLine ("}");
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: sb.ToString (), extraArgs: new [] { "-debug" });
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
foreach (var kw in objective_c_keywords)
|
|
mtouch.AssertError (4164, $"Cannot export the property 'X{kw}' because its selector '{kw}' is an Objective-C keyword. Please use a different name.", "testApp.cs");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4167 ()
|
|
{
|
|
var code = @"
|
|
class X : ReplayKit.RPBroadcastControllerDelegate
|
|
{
|
|
public override void DidUpdateServiceInfo (ReplayKit.RPBroadcastController broadcastController, NSDictionary<NSString, INSCoding> serviceInfo)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using System; using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecute ();
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4168 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var sb = new StringBuilder ();
|
|
foreach (var kw in objective_c_keywords) {
|
|
sb.AppendLine ($"[Foundation.Register (\"{kw}\")]");
|
|
sb.AppendLine ($"class X{kw} : Foundation.NSObject {{}}");
|
|
}
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: sb.ToString ());
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
foreach (var kw in objective_c_keywords)
|
|
mtouch.AssertError (4168, $"Cannot register the type 'X{kw}' because its Objective-C name '{kw}' is an Objective-C keyword. Please use a different name.");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4169 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var sb = new StringBuilder ();
|
|
sb.AppendLine (@"
|
|
[Foundation.Preserve (AllMembers = true)]
|
|
public class C
|
|
{
|
|
[System.Runtime.InteropServices.DllImport (""/usr/lib/libobjc.dylib"")]
|
|
static extern void objc_msgSend (object something);
|
|
}");
|
|
mtouch.Linker = MTouchLinker.LinkAll; // faster test
|
|
mtouch.CustomArguments = new string [] { "--marshal-objectivec-exceptions=throwmanaged" };
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: sb.ToString (), extraArgs: new [] { "-debug:full" });
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildDev, "build");
|
|
mtouch.AssertError (4169, $"Failed to generate a P/Invoke wrapper for objc_msgSend(System.Object): The registrar cannot get the ObjectiveC type for managed type `System.Object`.");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4170 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var code = @"
|
|
namespace NS {
|
|
using System;
|
|
using Foundation;
|
|
using ObjCRuntime;
|
|
class X : NSObject {
|
|
[Export (""a"")]
|
|
[return: BindAs (typeof (DateTime), OriginalType = typeof (NSNumber))]
|
|
DateTime A () { throw new NotImplementedException (); }
|
|
[Export (""b"")]
|
|
[return: BindAs (typeof (DateTime?), OriginalType = typeof (NSNumber))]
|
|
DateTime? B () { throw new NotImplementedException (); }
|
|
}
|
|
}";
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: code, extraArgs: new [] { "-debug" });
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertError (4170, "The registrar can't convert from 'System.DateTime' to 'Foundation.NSNumber' for the return value in the method NS.X.A.", "testApp.cs", 9);
|
|
mtouch.AssertError (4170, "The registrar can't convert from 'System.Nullable`1<System.DateTime>' to 'Foundation.NSNumber' for the return value in the method NS.X.B.", "testApp.cs", 12);
|
|
mtouch.AssertErrorCount (4 /* errors are duplicated */);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4171 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var code = @"
|
|
namespace NS {
|
|
using System;
|
|
using Foundation;
|
|
using ObjCRuntime;
|
|
class X : NSObject {
|
|
[Export (""a:"")]
|
|
void A ([BindAs (typeof (DateTime), OriginalType = typeof (NSNumber))] ConsoleColor value) {}
|
|
|
|
[Export (""b:"")]
|
|
void B ([BindAs (typeof (DateTime?), OriginalType = typeof (NSNumber))] ConsoleColor? value) {}
|
|
|
|
[Export (""C"")]
|
|
[return: BindAs (typeof (DateTime), OriginalType = typeof (NSNumber))]
|
|
ConsoleColor C () { throw new NotImplementedException (); }
|
|
|
|
[Export (""d"")]
|
|
[return: BindAs (typeof (DateTime?), OriginalType = typeof (NSNumber))]
|
|
ConsoleColor? D () { throw new NotImplementedException (); }
|
|
|
|
[Export (""E"")]
|
|
[BindAs (typeof (DateTime), OriginalType = typeof (NSNumber))]
|
|
ConsoleColor E { get; set; }
|
|
|
|
[Export (""F"")]
|
|
[BindAs (typeof (DateTime?), OriginalType = typeof (NSNumber))]
|
|
ConsoleColor? F { get; set; }
|
|
}
|
|
}";
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: code, extraArgs: new [] { "-debug" });
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertError (4138, "The registrar cannot marshal the property type 'System.ConsoleColor' of the property 'NS.X.E'.", "testApp.cs", 23);
|
|
mtouch.AssertError (4138, "The registrar cannot marshal the property type 'System.Nullable`1<System.ConsoleColor>' of the property 'NS.X.F'.", "testApp.cs", 27);
|
|
mtouch.AssertError (4171, "The BindAs attribute on the parameter #1 is invalid: the BindAs type System.DateTime is different from the parameter type System.ConsoleColor.", "testApp.cs", 8);
|
|
mtouch.AssertError (4171, "The BindAs attribute on the parameter #1 is invalid: the BindAs type System.Nullable`1<System.DateTime> is different from the parameter type System.Nullable`1<System.ConsoleColor>.", "testApp.cs", 11);
|
|
mtouch.AssertError (4171, "The BindAs attribute on the return value of the method NS.X.C is invalid: the BindAs type System.DateTime is different from the return type System.ConsoleColor.", "testApp.cs", 15);
|
|
mtouch.AssertError (4171, "The BindAs attribute on the return value of the method NS.X.D is invalid: the BindAs type System.Nullable`1<System.DateTime> is different from the return type System.Nullable`1<System.ConsoleColor>.", "testApp.cs", 19);
|
|
mtouch.AssertErrorCount (8 /* 2 errors are duplicated */);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4172 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var code = @"
|
|
namespace NS {
|
|
using System;
|
|
using Foundation;
|
|
using ObjCRuntime;
|
|
class X : NSObject {
|
|
[Export (""a:"")]
|
|
void A ([BindAs (typeof (DateTime), OriginalType = typeof (NSNumber))] DateTime value) {}
|
|
[Export (""b:"")]
|
|
void B ([BindAs (typeof (DateTime?), OriginalType = typeof (NSNumber))] DateTime? value) {}
|
|
[Export (""d:"")]
|
|
void D ([BindAs (typeof (int?[]), OriginalType = typeof (NSNumber[]))] int?[] value) {}
|
|
[Export (""e:"")]
|
|
void E ([BindAs (typeof (int), OriginalType = typeof (NSNumber))] ref int value) {}
|
|
[Export (""f:"")]
|
|
void F ([BindAs (typeof (int), OriginalType = typeof (NSNumber))] out int value) { throw new NotImplementedException (); }
|
|
[Export (""g:"")]
|
|
void G ([BindAs (typeof (int[,]), OriginalType = typeof (NSNumber[,]))] int[,] value) {}
|
|
[Export (""h:"")]
|
|
void H ([BindAs (typeof (int?[,]), OriginalType = typeof (NSNumber[,]))] int?[,] value) {}
|
|
}
|
|
enum E {
|
|
V,
|
|
}
|
|
class EClass : NSObject {
|
|
[Export (""a:"")]
|
|
void A ([BindAs (typeof (E), OriginalType = typeof (NSString))] E value) {}
|
|
[Export (""d:"")]
|
|
void D ([BindAs (typeof (E?[]), OriginalType = typeof (NSString[]))] E?[] value) {}
|
|
}
|
|
}";
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: code, extraArgs: new [] { "-debug" });
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.DateTime' to 'Foundation.NSNumber' for the parameter 'value' in the method NS.X.A.", "testApp.cs", 8);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.Nullable`1<System.DateTime>' to 'Foundation.NSNumber' for the parameter 'value' in the method NS.X.B.", "testApp.cs", 10);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.Nullable`1<System.Int32>[]' to 'Foundation.NSNumber[]' for the parameter 'value' in the method NS.X.D.", "testApp.cs", 12);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.Int32&' to 'Foundation.NSNumber' for the parameter 'value' in the method NS.X.E.", "testApp.cs", 14);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.Int32&' to 'Foundation.NSNumber' for the parameter 'value' in the method NS.X.F.", "testApp.cs", 16);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.Int32[0...,0...]' to 'Foundation.NSNumber[,]' for the parameter 'value' in the method NS.X.G.", "testApp.cs", 18);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.Nullable`1<System.Int32>[0...,0...]' to 'Foundation.NSNumber[,]' for the parameter 'value' in the method NS.X.H.", "testApp.cs", 20);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'NS.E' to 'Foundation.NSString' for the parameter 'value' in the method NS.EClass.A.", "testApp.cs", 27);
|
|
mtouch.AssertError (4172, "The registrar can't convert from 'System.Nullable`1<NS.E>[]' to 'Foundation.NSString[]' for the parameter 'value' in the method NS.EClass.D.", "testApp.cs", 29);
|
|
mtouch.AssertErrorCount (9);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4174 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var code = @"
|
|
namespace NS {
|
|
using System;
|
|
using Foundation;
|
|
using ObjCRuntime;
|
|
|
|
public class Consumer : NSObject, IProtocolWithOptionalMembers
|
|
{
|
|
[Export (""resolveRecipientsForSearchForMessages:withCompletion:"")]
|
|
public void ResolveRecipients (int arg, Action<bool> completion)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
}
|
|
|
|
|
|
[Protocol (Name = ""INSendMessageIntentHandling"", WrapperType = typeof (ProtocolWithOptionalMembersWrapper))]
|
|
[ProtocolMember (IsRequired = false, IsProperty = false, IsStatic = false, Name = ""ResolveRecipients"", Selector = ""resolveRecipientsForSendMessage:withCompletion:"", ParameterType = new Type [] { typeof (bool), typeof (global::System.Action<bool>) }, ParameterByRef = new bool [] { false, false })]
|
|
public interface IProtocolWithOptionalMembers : INativeObject, IDisposable
|
|
{
|
|
}
|
|
|
|
public static partial class ProtocolWithOptionalMembers_Extensions {
|
|
[BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
|
|
public static void ResolveRecipients (this IProtocolWithOptionalMembers This, bool arg, [BlockProxy (typeof (NIDActionArity1V89))]global::System.Action<bool> completion)
|
|
{
|
|
}
|
|
}
|
|
|
|
internal sealed class ProtocolWithOptionalMembersWrapper : BaseWrapper, IProtocolWithOptionalMembers {
|
|
[Preserve (Conditional = true)]
|
|
public ProtocolWithOptionalMembersWrapper (IntPtr handle, bool owns)
|
|
: base (handle, owns)
|
|
{
|
|
}
|
|
}
|
|
|
|
[UserDelegateType (typeof (global::System.Action<bool>))]
|
|
internal delegate void DActionArity1V89 (IntPtr block, IntPtr obj);
|
|
|
|
static internal class SDActionArity1V89 {
|
|
static internal readonly DActionArity1V89 Handler = Invoke;
|
|
|
|
[MonoPInvokeCallback (typeof (DActionArity1V89))]
|
|
static void Invoke (IntPtr block, IntPtr obj) {
|
|
throw new NotImplementedException ();
|
|
}
|
|
}
|
|
|
|
internal class NIDActionArity1V89 {
|
|
IntPtr blockPtr;
|
|
DActionArity1V89 invoker;
|
|
|
|
[Preserve (Conditional=true)]
|
|
[BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
|
|
public NIDActionArity1V89 (ref BlockLiteral block)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[Preserve (Conditional=true)]
|
|
[BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
|
|
~NIDActionArity1V89 ()
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[Preserve (Conditional=true)]
|
|
[BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
|
|
public static global::System.Action<bool> Create (IntPtr block)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[Preserve (Conditional=true)]
|
|
[BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
|
|
void Invoke (bool obj)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
";
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: code, extraArgs: new [] { "-debug" });
|
|
mtouch.WarnAsError = new int [] { 4174 };
|
|
mtouch.AssertExecuteFailure ("build");
|
|
mtouch.AssertError (4174, "Unable to locate the block to delegate conversion method for the method NS.Consumer.ResolveRecipients's parameter #2.", "testApp.cs", 11);
|
|
mtouch.AssertErrorCount (1);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4176 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var code = @"
|
|
namespace NS {
|
|
using System;
|
|
using Foundation;
|
|
using ObjCRuntime;
|
|
|
|
public class Consumer : NSObject
|
|
{
|
|
[Export (""getAction"")]
|
|
public Action GetFunction ()
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[Export (""getProperty"")]
|
|
public Action GetProperty {
|
|
get {
|
|
throw new NotImplementedException ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
";
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.CreateTemporaryApp (extraCode: code, extraArgs: new [] { "-debug" });
|
|
mtouch.WarnAsError = new int [] { 4176 };
|
|
mtouch.AssertExecuteFailure ("build");
|
|
mtouch.AssertError (4176, "Unable to locate the delegate to block conversion type for the return value of the method NS.Consumer.GetFunction.", "testApp.cs", 11);
|
|
mtouch.AssertError (4176, "Unable to locate the delegate to block conversion type for the return value of the method NS.Consumer.get_GetProperty.", "testApp.cs", 17);
|
|
mtouch.AssertErrorCount (2);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void NoWarnings ()
|
|
{
|
|
var code = @"
|
|
public partial class MyTableViewCell : UITableViewCell {
|
|
protected MyTableViewCell (IntPtr handle) : base (handle)
|
|
{
|
|
}
|
|
|
|
public override void AwakeFromNib ()
|
|
{
|
|
base.AwakeFromNib ();
|
|
}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using UIKit; using Foundation; using System;");
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink; // so that as much as possible is registered
|
|
mtouch.Verbosity = 9; // Increase verbosity, otherwise linker warnings aren't shown
|
|
mtouch.AssertExecute (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertNoWarnings ();
|
|
foreach (var line in mtouch.OutputLines) {
|
|
if (line.Contains ("warning: method 'paymentAuthorizationViewController:didAuthorizePayment:handler:' in protocol 'PKPaymentAuthorizationViewControllerDelegate' not implemented [-Wprotocol]"))
|
|
continue; // Xcode 9 beta 1: this method changed from optional to required.
|
|
Assert.That (line, Does.Not.Match ("warning:"), "no warnings");
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MultiplePropertiesInHierarchy ()
|
|
{
|
|
// https://bugzilla.xamarin.com/show_bug.cgi?id=18337
|
|
|
|
var code = @"
|
|
class C : NSObject {
|
|
[Outlet]
|
|
string Foo { get; set; }
|
|
}
|
|
class D : C {
|
|
[Outlet]
|
|
string Foo { get; set; }
|
|
}
|
|
|
|
class E : NSObject {
|
|
[Export (""foo"")]
|
|
string Foo { get; set; }
|
|
}
|
|
|
|
class F : E {
|
|
[Export (""foo"")]
|
|
string Foo { get; set; }
|
|
}
|
|
|
|
class G : NSObject {
|
|
[Connect ()]
|
|
NSString Foo { get; set; }
|
|
}
|
|
|
|
class H : G {
|
|
[Connect ()]
|
|
NSString Foo { get; set; }
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecute ();
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericType_Warnings ()
|
|
{
|
|
var code = @"
|
|
class Open<T> : NSObject {}
|
|
class Closed : Open<UIView> {}
|
|
class Generic2<T> : NSObject where T: struct {}
|
|
class Generic3<T> : NSObject where T: System.IConvertible {}
|
|
";
|
|
|
|
// and the lack of warnings/errors in the new static registrar.
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using UIKit;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecute ();
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericType_NonConstrainedTypeArguments ()
|
|
{
|
|
var code = @"
|
|
class Open<U, V> : NSObject where U: NSObject
|
|
{
|
|
[Export (""foo:"")]
|
|
public void Foo (V arg) {} // Not OK
|
|
|
|
[Export (""foozap"")]
|
|
public V FooZap { get { return default (V); } } // Not OK
|
|
|
|
[Export (""bar"")]
|
|
public V Bar { get; set; }
|
|
}";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4132, "The registrar found an invalid generic return type 'V' in the property 'Open`2.FooZap'. The return type must have an 'NSObject' constraint.", "testApp.cs", 9);
|
|
mtouch.AssertError (4132, "The registrar found an invalid generic return type 'V' in the property 'Open`2.Bar'. The return type must have an 'NSObject' constraint.", "testApp.cs", 12);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'V' in the parameter arg of the method 'Open`2.Foo(V)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 6);
|
|
mtouch.AssertErrorCount (3);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericType_StaticMembersOnOpenGenericType ()
|
|
{
|
|
var code = @"
|
|
class Open<U> : NSObject
|
|
{
|
|
[Export (""foo"")]
|
|
public static void Foo () {} // Not OK
|
|
|
|
[Export (""foo:"")]
|
|
public static void Foo (U arg) {} // Not OK
|
|
|
|
[Export (""zap"")]
|
|
public static string Zap { get; set; } // Not OK
|
|
}
|
|
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4131, "The registrar cannot export static properties in generic classes ('Open`1.Zap').", "testApp.cs", 12);
|
|
mtouch.AssertError (4130, "The registrar cannot export static methods in generic classes ('Open`1.Foo()').", "testApp.cs", 6);
|
|
mtouch.AssertError (4130, "The registrar cannot export static methods in generic classes ('Open`1.Foo(U)').", "testApp.cs", 9);
|
|
mtouch.AssertErrorCount (3);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void NestedGenericType ()
|
|
{
|
|
var code = @"
|
|
|
|
class Parent<T> {
|
|
public class Nested : NSObject {
|
|
[Export (""foo:"")]
|
|
public void Foo (T foo) {
|
|
}
|
|
}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'T' in the parameter foo of the method 'Parent`1/Nested.Foo(T)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 7);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericType_WithDerivedClosedOverride ()
|
|
{
|
|
var code = @"
|
|
class GenericTestClass<T> : NSObject
|
|
{
|
|
[Export (""arg1:"")]
|
|
public virtual void Arg1 (T t) {}
|
|
}
|
|
|
|
class DerivedClosed : GenericTestClass <UIView>
|
|
{
|
|
public override void Arg1 (UIView t) {}
|
|
}
|
|
";
|
|
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using UIKit;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'T' in the parameter t of the method 'GenericTestClass`1.Arg1(T)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 6);
|
|
mtouch.AssertErrorCount (1);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericType_WithInvalidParameterTypes ()
|
|
{
|
|
var code = @"
|
|
using System.Collections.Generic;
|
|
using Foundation;
|
|
class Open<U> : NSObject where U: NSObject
|
|
{
|
|
[Export (""bar:"")]
|
|
public void Bar (List<U> arg) {} // Not OK, can't marshal lists.
|
|
}
|
|
class C { static void Main () {} }
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (code: code, extraArgs: new [] { "-debug:full" });
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster test
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Collections.Generic.List`1<U>' of the parameter 'arg' in the method 'Open`1.Bar(System.Collections.Generic.List`1<U>)'", "testApp.cs", 7);
|
|
mtouch.AssertErrorCount (1);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericType_WithINativeObjectConstraint ()
|
|
{
|
|
var code = @"
|
|
class Open<U> : NSObject where U: INativeObject
|
|
{
|
|
[Export (""bar:"")]
|
|
public void Bar (U arg) {} // Not OK
|
|
|
|
[Export (""zap:"")]
|
|
public void Zap (U[] arg) {} // Not OK
|
|
|
|
[Export (""xyz"")]
|
|
public U XyZ () { return default (U); } // Not OK
|
|
|
|
[Export (""barzap"")]
|
|
public U BarZap { get { return default (U); } } // Not OK
|
|
|
|
[Export (""zapbar"")]
|
|
public Action<U> ZapBar () { return null; } // Not OK
|
|
|
|
[Export (""xyz"")]
|
|
public void XyZ (Action<U> f) {}
|
|
|
|
[Export (""foozap"")]
|
|
public void FooZap (List<List<List<List<U>>>> f) {}
|
|
|
|
[Export (""zapfoo"")]
|
|
public List<List<U>> ZapBoo () { return null; }
|
|
|
|
[Export (""f1"")]
|
|
public U F1 { get; set; }
|
|
|
|
[Export (""f2"")]
|
|
public List<List<U>> F2 { get { return null; } }
|
|
|
|
[Export (""f3"")]
|
|
public Action<U> F3 { set { } }
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using System; using System.Collections.Generic; using ObjCRuntime;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4132, "The registrar found an invalid generic return type 'U' in the property 'Open`1.BarZap'. The return type must have an 'NSObject' constraint.", "testApp.cs", 15);
|
|
mtouch.AssertError (4132, "The registrar found an invalid generic return type 'U' in the property 'Open`1.F1'. The return type must have an 'NSObject' constraint.", "testApp.cs", 30);
|
|
mtouch.AssertError (4132, "The registrar found an invalid generic return type 'System.Collections.Generic.List`1<System.Collections.Generic.List`1<U>>' in the property 'Open`1.F2'. The return type must have an 'NSObject' constraint.", "testApp.cs", 33);
|
|
mtouch.AssertError (4132, "The registrar found an invalid generic return type 'System.Action`1<U>' in the property 'Open`1.F3'. The return type must have an 'NSObject' constraint.", "testApp.cs", 36);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'U' in the parameter arg of the method 'Open`1.Bar(U)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 6);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'U[]' in the parameter arg of the method 'Open`1.Zap(U[])'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 9);
|
|
mtouch.AssertError (4129, "The registrar found an invalid generic return type 'U' in the method 'Open`1.XyZ()'. The generic return type must have an 'NSObject' constraint.", "testApp.cs", 12);
|
|
mtouch.AssertError (4129, "The registrar found an invalid generic return type 'System.Action`1<U>' in the method 'Open`1.ZapBar()'. The generic return type must have an 'NSObject' constraint.", "testApp.cs", 18);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'System.Action`1<U>' in the parameter f of the method 'Open`1.XyZ(System.Action`1<U>)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 21);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'System.Collections.Generic.List`1<System.Collections.Generic.List`1<System.Collections.Generic.List`1<System.Collections.Generic.List`1<U>>>>' in the parameter f of the method 'Open`1.FooZap(System.Collections.Generic.List`1<System.Collections.Generic.List`1<System.Collections.Generic.List`1<System.Collections.Generic.List`1<U>>>>)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 24);
|
|
mtouch.AssertError (4129, "The registrar found an invalid generic return type 'System.Collections.Generic.List`1<System.Collections.Generic.List`1<U>>' in the method 'Open`1.ZapBoo()'. The generic return type must have an 'NSObject' constraint.", "testApp.cs", 27);
|
|
mtouch.AssertErrorCount (11);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericType_WithINativeObjectConstraint2 ()
|
|
{
|
|
var code = @"
|
|
unsafe class Open<U> : NSObject where U: INativeObject
|
|
{
|
|
[Export (""bar:"")]
|
|
public void Bar (ref U arg) {} // Not OK
|
|
|
|
[Export (""zap:"")]
|
|
public void Zap (out U[] arg) { arg = null; } // Not OK
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation; using ObjCRuntime;", extraArgs: new [] { "/debug:full", "/unsafe" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'U&' in the parameter arg of the method 'Open`1.Bar(U&)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 6);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'U[]&' in the parameter arg of the method 'Open`1.Zap(U[]&)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 9);
|
|
mtouch.AssertErrorCount (2);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericMethods ()
|
|
{
|
|
var str1 = @"
|
|
[Register (""GenericMethodClass"")]
|
|
class GenericMethodClass : NSObject {
|
|
[Export (""foo:"")]
|
|
public static void Foo<T> (T foo) {}
|
|
[Export (""GenericMethod"")]
|
|
public virtual void GenericMethod<T> (T foo) { }
|
|
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: str1, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'GenericMethodClass.Foo(T)'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 6);
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'GenericMethodClass.GenericMethod(T)'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 8);
|
|
mtouch.AssertErrorCount (2);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericMethods1 ()
|
|
{
|
|
var code = @"
|
|
class GenericMethodClass : NSObject {
|
|
[Export (""Foo:"")]
|
|
public virtual void Foo (System.Action<string> func) {}
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "/debug:full" });
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.AssertExecute ();
|
|
mtouch.AssertWarning (4174, "Unable to locate the block to delegate conversion method for the method GenericMethodClass.Foo's parameter #1.", "testApp.cs", 5);
|
|
mtouch.AssertWarningCount (1);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericMethods2 ()
|
|
{
|
|
var str1 = @"
|
|
using Foundation;
|
|
class NullableGenericTestClass<T> : NSObject where T: struct
|
|
{
|
|
[Export (""init:"")]
|
|
public NullableGenericTestClass (T? foo)
|
|
{
|
|
}
|
|
|
|
[Export (""Z1:"")]
|
|
public void Z1<Z> (Z? foo) where Z: struct
|
|
{
|
|
}
|
|
|
|
[Export (""Z2"")]
|
|
public Z Z2<Z> () where Z: struct
|
|
{
|
|
throw new System.NotImplementedException ();
|
|
}
|
|
|
|
[Export (""Z3"")]
|
|
public void Z3<Z> (Z foo)
|
|
{
|
|
}
|
|
|
|
[Export (""T1"")]
|
|
public void T1 (T foo)
|
|
{
|
|
}
|
|
|
|
[Export (""T2:"")]
|
|
public void T2 (T? foo)
|
|
{
|
|
}
|
|
|
|
[Export (""T3"")]
|
|
public T T3 ()
|
|
{
|
|
throw new System.NotImplementedException ();
|
|
}
|
|
}
|
|
class C { static void Main () {} }
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (code: str1, extraArgs: new [] { "-debug:full" });
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster test
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'NullableGenericTestClass`1.Z1(System.Nullable`1<Z>)'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 12);
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'NullableGenericTestClass`1.Z2()'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 17);
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'NullableGenericTestClass`1.Z3(Z)'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 23);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'T' in the parameter foo of the method 'NullableGenericTestClass`1.T1(T)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 28);
|
|
mtouch.AssertError (4128, "The registrar found an invalid generic parameter type 'System.Nullable`1<T>' in the parameter foo of the method 'NullableGenericTestClass`1.T2(System.Nullable`1<T>)'. The generic parameter must have an 'NSObject' constraint.", "testApp.cs", 33);
|
|
mtouch.AssertError (4129, "The registrar found an invalid generic return type 'T' in the method 'NullableGenericTestClass`1.T3()'. The generic return type must have an 'NSObject' constraint.", "testApp.cs", 38);
|
|
mtouch.AssertError (4136, "The registrar cannot marshal the parameter type 'System.Nullable`1<T>' of the parameter 'foo' in the method 'NullableGenericTestClass`1..ctor(System.Nullable`1<T>)'", "testApp.cs", 6);
|
|
mtouch.AssertErrorCount (7);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenericMethods3 ()
|
|
{
|
|
var code = @"
|
|
|
|
class G : NSObject {
|
|
[Export (""fooX1:"")]
|
|
public virtual X Foo1<X> (int x) where X : NSObject { return default(X); }// Not OK
|
|
|
|
[Export (""fooX2:"")]
|
|
public virtual X Foo2<X> (int x) { return default(X); } // Not OK
|
|
|
|
[Export (""fooX3:"")]
|
|
public void Foo3<X> (X x) { } // Not OK
|
|
}
|
|
";
|
|
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using Foundation;", extraArgs: new [] { "-debug:full" });
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink; // faster test
|
|
mtouch.AssertExecuteFailure ();
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'G.Foo1(System.Int32)'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 6);
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'G.Foo2(System.Int32)'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 9);
|
|
mtouch.AssertError (4113, "The registrar found a generic method: 'G.Foo3(X)'. Exporting generic methods is not supported, and will lead to random behavior and/or crashes", "testApp.cs", 12);
|
|
mtouch.AssertErrorCount (3);
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ConformsToProtocolTest ()
|
|
{
|
|
var code = @"
|
|
class CTP : NSObject {
|
|
public override bool ConformsToProtocol (IntPtr protocol) { return base.ConformsToProtocol (protocol); }
|
|
}
|
|
|
|
class CTP1 : NSObject {
|
|
public override bool ConformsToProtocol (IntPtr protocol) { return base.ConformsToProtocol (protocol); }
|
|
}
|
|
class CTP2 : CTP1 {
|
|
public override bool ConformsToProtocol (IntPtr protocol) { return base.ConformsToProtocol (protocol); }
|
|
}
|
|
|
|
|
|
class CTP3 : NSObject { }
|
|
class CTP4 : CTP3 {
|
|
public override bool ConformsToProtocol (IntPtr protocol) { return base.ConformsToProtocol (protocol); }
|
|
}
|
|
";
|
|
using (var mtouch = new MTouchTool ()) {
|
|
mtouch.CreateTemporaryCacheDirectory ();
|
|
mtouch.CreateTemporaryApp (extraCode: code, usings: "using System; using Foundation;");
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.AssertExecute ();
|
|
mtouch.AssertNoWarnings ();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4177 ()
|
|
{
|
|
// newline is invalid, but it messes up the error message and testing is just annoying, so skip it.
|
|
var testInvalidCharacters = invalidSelectorCharacters.Where ((v) => v != '\n').ToArray ();
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var sb = new StringBuilder ();
|
|
for (int i = 0; i < testInvalidCharacters.Length; i++) {
|
|
var c = testInvalidCharacters [i];
|
|
var str = c.ToString ();
|
|
if (c == '"')
|
|
str = "\"\"";
|
|
sb.AppendLine ();
|
|
sb.AppendLine ($"[ObjCRuntime.Adopts (@\"Foo{str}\")]");
|
|
sb.AppendLine ($"public class TestInvalidChar{i} : Foundation.NSObject {{");
|
|
sb.AppendLine ("}");
|
|
}
|
|
|
|
mtouch.CreateTemporaryApp (extraCode: sb.ToString (), extraArgs: new [] { "-debug" });
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
|
|
for (int i = 0; i < testInvalidCharacters.Length; i++) {
|
|
var c = testInvalidCharacters [i];
|
|
var str = c.ToString ();
|
|
if (c == '"')
|
|
str = "\"";
|
|
mtouch.AssertError (4177, $"The 'ProtocolType' parameter of the 'Adopts' attribute used in class 'TestInvalidChar{i}' contains an invalid character. Value used: 'Foo{str}' Invalid Char: '{c}'");
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void MT4179 ()
|
|
{
|
|
using (var mtouch = new MTouchTool ()) {
|
|
var code = @"
|
|
using System;
|
|
|
|
using Foundation;
|
|
using ObjCRuntime;
|
|
|
|
abstract class SomeNativeObject : INativeObject
|
|
{
|
|
public IntPtr Handle { get; set; }
|
|
SomeNativeObject (IntPtr handle, bool owns) { }
|
|
}
|
|
|
|
class C : NSObject {
|
|
[Export (""M1:"")]
|
|
public void M1 (SomeNativeObject obj)
|
|
{
|
|
}
|
|
|
|
[Export (""M2"")]
|
|
public SomeNativeObject M2 ()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
[Export (""M3"")]
|
|
public SomeNativeObject M3 {
|
|
get;
|
|
set;
|
|
}
|
|
static void Main () {}
|
|
}
|
|
";
|
|
|
|
mtouch.CreateTemporaryApp (code: code, extraArgs: new [] { "-debug" });
|
|
mtouch.Registrar = MTouchRegistrar.Static;
|
|
mtouch.Linker = MTouchLinker.DontLink;
|
|
mtouch.AssertExecute (MTouchAction.BuildSim, "build");
|
|
mtouch.AssertWarningCount (4);
|
|
mtouch.AssertWarning (4179, $"The registrar found the abstract type 'SomeNativeObject' in the signature for 'C.get_M3'. Abstract types should not be used in the signature for a member exported to Objective-C.", "testApp.cs", 27);
|
|
mtouch.AssertWarning (4179, $"The registrar found the abstract type 'SomeNativeObject' in the signature for 'C.set_M3'. Abstract types should not be used in the signature for a member exported to Objective-C.", "testApp.cs", 28);
|
|
mtouch.AssertWarning (4179, $"The registrar found the abstract type 'SomeNativeObject' in the signature for 'C.M1'. Abstract types should not be used in the signature for a member exported to Objective-C.", "testApp.cs", 16);
|
|
mtouch.AssertWarning (4179, $"The registrar found the abstract type 'SomeNativeObject' in the signature for 'C.M2'. Abstract types should not be used in the signature for a member exported to Objective-C.", "testApp.cs", 21);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|