Skip to content

Commit

Permalink
Merge c37aba5 into 775cedf
Browse files Browse the repository at this point in the history
  • Loading branch information
monojenkins committed Jul 8, 2019
2 parents 775cedf + c37aba5 commit 1bde353
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 4 deletions.
39 changes: 39 additions & 0 deletions src/ObjCRuntime/Registrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ internal class ObjCType {
public CategoryAttribute CategoryAttribute;
public TType Type;
public ObjCType BaseType;
// This only contains the leaf protocols implemented by this type.
public ObjCType [] Protocols;
public string [] AdoptedProtocols;
public bool IsModel;
Expand All @@ -159,6 +160,44 @@ internal class ObjCType {

public bool IsCategory { get { return CategoryAttribute != null; } }

#if MTOUCH || MMP
HashSet<ObjCType> all_protocols;
// This contains all protocols in the type hierarchy.
// Given a type T that implements a protocol with super protocols:
// class T : NSObject, IProtocol2 {}
// [Protocol]
// interface IP1 {}
// [Protocol]
// interface IP2 : IP1 {}
// This property will contain both IP1 and IP2. The Protocols property only contains IP2.
public IEnumerable<ObjCType> AllProtocols {
get {
if (Protocols == null || Protocols.Length == 0)
return null;

if (all_protocols == null) {
var queue = new Queue<ObjCType> (Protocols);
var rv = new HashSet<ObjCType> ();
while (queue.Count > 0) {
var type = queue.Dequeue ();
if (rv.Add (type)) {
foreach (var iface in type.Type.Resolve ().Interfaces) {
if (!Registrar.Types.TryGetValue (iface.InterfaceType, out var superIface)) {
// This is not an interface that corresponds to a protocol.
continue;
}
queue.Enqueue (superIface);
}
}
}
all_protocols = rv;
}

return all_protocols;
}
}
#endif

public void VerifyRegisterAttribute (ref List<Exception> exceptions)
{
if (RegisterAttribute == null)
Expand Down
138 changes: 138 additions & 0 deletions tests/monotouch-test/Foundation/UrlProtocolTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

#if XAMCORE_2_0
using Foundation;
#if MONOMAC
Expand Down Expand Up @@ -66,5 +69,140 @@ public void Task ()
}
}
#endif

#if !__WATCHOS__
[Test]
public void RegistrarTest ()
{
Exception ex = null;
var done = new ManualResetEvent (false);
var success = false;

Task.Run (async () => {
try {
var config = NSUrlSessionConfiguration.DefaultSessionConfiguration;
config.WeakProtocolClasses = NSArray.FromNSObjects (new Class (typeof (CustomUrlProtocol)));
var session = NSUrlSession.FromConfiguration (config);
var custom_url = new NSUrl ("foo://server");
using (var task = await session.CreateDownloadTaskAsync (custom_url)) {
success = true;
}
} catch (Exception e) {
ex = e;
} finally {
done.Set ();
}
});

Assert.IsTrue (TestRuntime.RunAsync (DateTime.Now.AddSeconds (10), () => { }, () => done.WaitOne (0)), "Timed out");
Assert.IsNull (ex, "Exception");
Assert.IsTrue (custom_url_protocol_instance.Called_DidCompleteWithError, "DidCompleteWithError");
// if DidReceiveChallenge is called or not seems to vary between test runs, so we can't assert it.
//Assert.IsFalse (custom_url_protocol_instance.Called_DidReceiveChallenge, "DidReceiveChallenge");
Assert.IsTrue (custom_url_protocol_instance.Called_DidReceiveData, "DidReceiveData");
Assert.IsTrue (custom_url_protocol_instance.Called_DidReceiveResponse, "DidReceiveResponse");
Assert.IsTrue (custom_url_protocol_instance.Called_StartLoading, "StartLoading");
Assert.IsTrue (custom_url_protocol_instance.Called_StopLoading, "StopLoading");
Assert.IsTrue (custom_url_protocol_instance.Called_WillPerformHttpRedirection, "WillPerformHttpRedirection");

Assert.IsTrue (CustomUrlProtocol.Called_CanInitWithRequest, "CanInitWithRequest");
Assert.IsTrue (CustomUrlProtocol.Called_GetCanonicalRequest, "GetCanonicalRequest");

Assert.IsTrue (success, "Success");
}

static CustomUrlProtocol custom_url_protocol_instance;

public class CustomUrlProtocol : NSUrlProtocol, INSUrlSessionDelegate, INSUrlSessionTaskDelegate, INSUrlSessionDataDelegate {
[Export ("canInitWithRequest:")]
public static new bool CanInitWithRequest (NSUrlRequest request)
{
Called_CanInitWithRequest = true;
return true;
}
public static bool Called_CanInitWithRequest;

[Export ("canonicalRequestForRequest:")]
public static new NSUrlRequest GetCanonicalRequest (NSUrlRequest request)
{
Called_GetCanonicalRequest = true;
return request;
}
public static bool Called_GetCanonicalRequest;

[Export ("initWithRequest:cachedResponse:client:")]
public CustomUrlProtocol (NSUrlRequest request, NSCachedUrlResponse cachedResponse, INSUrlProtocolClient client)
: base (request, cachedResponse, client)
{
custom_url_protocol_instance = this;
}

[Export ("startLoading")]
public override void StartLoading ()
{
Called_StartLoading = true;
var config = NSUrlSession.SharedSession.Configuration;
var session = NSUrlSession.FromConfiguration (config, this, new NSOperationQueue ());

var task = session.CreateDataTask (new NSUrlRequest (new NSUrl ("https://microsoft.com")));
task.Resume ();
}
public bool Called_StartLoading;

[Export ("stopLoading")]
public override void StopLoading ()
{
Called_StopLoading = true;
}
public bool Called_StopLoading;

//NSURLSessionTaskDelegate
[Export ("URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:")]
public virtual void WillPerformHttpRedirection (NSUrlSession session, NSUrlSessionTask task, NSHttpUrlResponse response, NSUrlRequest newRequest, Action<NSUrlRequest> completionHandler)
{
Called_WillPerformHttpRedirection = true;
completionHandler (newRequest);
}
public bool Called_WillPerformHttpRedirection;

[Export ("URLSession:task:didReceiveChallenge:completionHandler:")]
public virtual void DidReceiveChallenge (NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
Called_DidReceiveChallenge = true;
completionHandler (NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, null);
}
public bool Called_DidReceiveChallenge;

//NSURLSessionDataDelegate
[Export ("URLSession:dataTask:didReceiveResponse:completionHandler:")]
public virtual void DidReceiveResponse (NSUrlSession session, NSUrlSessionDataTask dataTask, NSUrlResponse response, Action<NSUrlSessionResponseDisposition> completionHandler)
{
Called_DidReceiveResponse = true;
completionHandler (NSUrlSessionResponseDisposition.Allow);
this.Client.ReceivedResponse (this, response, NSUrlCacheStoragePolicy.Allowed);
}
public bool Called_DidReceiveResponse;

[Export ("URLSession:dataTask:didReceiveData:")]
public virtual void DidReceiveData (NSUrlSession session, NSUrlSessionDataTask dataTask, NSData data)
{
Called_DidReceiveData = true;
this.Client.DataLoaded (this, data);
}
public bool Called_DidReceiveData;

[Export ("URLSession:task:didCompleteWithError:")]
public virtual void DidCompleteWithError (NSUrlSession session, NSUrlSessionTask task, NSError error)
{
Called_DidCompleteWithError = true;
if (error != null) {
this.Client.FailedWithError (this, error);
} else {
this.Client.FinishedLoading (this);
}
}
public bool Called_DidCompleteWithError;
}
#endif // !__WATCHOS__
}
}
10 changes: 6 additions & 4 deletions tools/common/StaticRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4129,10 +4129,11 @@ TypeDefinition GetDelegateProxyType (ObjCMethod obj_method)
}

// Might be an implementation of an optional protocol member.
if (obj_method.DeclaringType.Protocols != null) {
var allProtocols = obj_method.DeclaringType.AllProtocols;
if (allProtocols != null) {
string selector = null;

foreach (var proto in obj_method.DeclaringType.Protocols) {
foreach (var proto in allProtocols) {
// We store the DelegateProxy type in the ProtocolMemberAttribute, so check those.
if (selector == null)
selector = obj_method.Selector ?? string.Empty;
Expand Down Expand Up @@ -4175,10 +4176,11 @@ MethodDefinition GetBlockWrapperCreator (ObjCMethod obj_method, int parameter)
}

// Might be an implementation of an optional protocol member.
if (obj_method.DeclaringType.Protocols != null) {
var allProtocols = obj_method.DeclaringType.AllProtocols;
if (allProtocols != null) {
string selector = null;

foreach (var proto in obj_method.DeclaringType.Protocols) {
foreach (var proto in allProtocols) {
// We store the BlockProxy type in the ProtocolMemberAttribute, so check those.
// We may run into binding assemblies built with earlier versions of the generator,
// which means we can't rely on finding the BlockProxy attribute in the ProtocolMemberAttribute.
Expand Down

0 comments on commit 1bde353

Please sign in to comment.