using System; using System.IO; using System.Collections.Generic; using System.Reflection; using NUnit.Framework; #if XAMCORE_2_0 using Foundation; using ObjCRuntime; #elif MONOMAC using MonoMac.Foundation; using MonoMac.ObjCRuntime; #else using MonoTouch.Foundation; using MonoTouch.ObjCRuntime; #endif namespace Introspection { [Preserve (AllMembers = true)] public abstract class ApiWeakPropertyTest : ApiBaseTest { /// /// Override if you want to skip testing the specified type. /// /// Type to be tested protected virtual bool Skip (Type type) { switch (type.Name) { case "LinkWithAttribute": // LinkWithAttribute.WeakFrameworks return true; } return false; } /// /// Override if you want to skip testing the specified property. /// /// Property candidate. protected virtual bool Skip (PropertyInfo property) { switch (property.Name) { // the selector starts with `weak` case "WeakRelatedUniqueIdentifier": return property.DeclaringType.Name == "CSSearchableItemAttributeSet"; } return false; } [Test] public void WeakPropertiesHaveArgumentSemantic () { var failed_properties = new List (); Errors = 0; int c = 0, n = 0; foreach (Type t in Assembly.GetTypes ()) { if (Skip (t) || SkipDueToAttribute (t)) continue; if (LogProgress) Console.WriteLine ("{0}. {1}", c++, t.FullName); foreach (var p in t.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { // looking for properties with setters only if (!p.CanWrite) continue; if (SkipDueToAttribute (p)) continue; if (Skip (p)) continue; string name = p.Name; if (!name.StartsWith ("Weak", StringComparison.Ordinal)) continue; string error; if (CheckArgumentSemantic (p.GetMethod, out error)) { ReportError (error); failed_properties.Add (p.ToString ()); } if (CheckArgumentSemantic (p.SetMethod, out error)) { ReportError (error); failed_properties.Add (p.ToString ()); } n++; } } Assert.AreEqual (0, Errors, "{0} errors found in {1} fields validated: {2}", Errors, n, string.Join (", ", failed_properties)); } bool CheckArgumentSemantic (MethodInfo meth, out string error) { error = null; var export = meth.GetCustomAttribute (); if (export == null) { error = String.Format ("{0}.{1} has no [Export]", meth.DeclaringType.FullName, meth.Name); return true; } switch (export.ArgumentSemantic) { case ArgumentSemantic.Assign: // Also case ArgumentSemantic.UnsafeUnretained: case ArgumentSemantic.Copy: case ArgumentSemantic.Retain: // case ArgumentSemantic.Strong: case ArgumentSemantic.Weak: return false; default: error = String.Format ("{0}.{1} has incorrect ArgumentSemantics: {2}", meth.DeclaringType.FullName, meth.Name, export.ArgumentSemantic); return true; } } } }