[tests][intro] Add checks for [Field] that should have [Notification] attributes (#1289)

Also:

* some refactoring to reduce the reflection usage for each field-based
  introspection tests;

* some fixes for existing bindings, mostly missing [Notification]

* removal of `unsafe` in the notification binding generation (not needed)

* Ignore the new test on XM until the API have been fixed
This commit is contained in:
Sebastien Pouliot 2016-12-02 12:05:05 -05:00 коммит произвёл GitHub
Родитель 33b677b763
Коммит 16c2200804
6 изменённых файлов: 118 добавлений и 65 удалений

Просмотреть файл

@ -8,7 +8,7 @@
// Copyright 2014, Xamarin Inc. All rights reserved.
//
#if !XAMCORE_2_0
#if IOS
using System;
using XamCore.ObjCRuntime;
@ -17,6 +17,7 @@ using XamCore.Foundation;
namespace XamCore.UIKit {
public partial class UIWindow {
#if !XAMCORE_2_0
// we already have a UIWindowLevel static class for the constants
[Obsolete ("Use UIWindowLevel.Normal")]
public const float LevelNormal = 0f;
@ -26,6 +27,18 @@ namespace XamCore.UIKit {
[Obsolete ("Use UIWindowLevel.StatusBar")]
public const float LevelStatusBar = 1000f;
#endif
#if !XAMCORE_4_0
// duplicates from UIKeyboard without a [Notification]
public static NSString KeyboardDidChangeFrameNotification {
get { return UIKeyboard.DidChangeFrameNotification; }
}
public static NSString KeyboardWillChangeFrameNotification {
get { return UIKeyboard.WillChangeFrameNotification; }
}
#endif
}
}

Просмотреть файл

@ -6334,7 +6334,7 @@ public partial class Generator : IMemberGatherer {
if (HasAttribute (field_pi, typeof (NotificationAttribute)))
print ($"[Advice (\"Use {type.Name}.Notifications.Observe{GetNotificationName (field_pi)} helper method instead.\")]");
print ("{0} static unsafe {1} {2}{3} {{", field_pi.IsInternal () ? "internal" : "public", fieldTypeName,
print ("{0} static {1} {2}{3} {{", field_pi.IsInternal () ? "internal" : "public", fieldTypeName,
field_pi.Name,
is_unified_internal ? "_" : "");
indent++;

Просмотреть файл

@ -385,6 +385,7 @@ namespace XamCore.HomeKit {
[Field ("HMCharacteristicPropertyHidden")]
NSString Hidden { get; }
[Notification]
[Field ("HMCharacteristicPropertySupportsEventNotification")]
NSString SupportsEventNotification { get; }
}

Просмотреть файл

@ -1227,10 +1227,12 @@ namespace XamCore.MediaPlayer {
UIImage VolumeWarningSliderImage { get; set; }
[Since (7,0)]
[Notification]
[Field ("MPVolumeViewWirelessRoutesAvailableDidChangeNotification")]
NSString WirelessRoutesAvailableDidChangeNotification { get; }
[Since (7,0)]
[Notification]
[Field ("MPVolumeViewWirelessRouteActiveDidChangeNotification")]
NSString WirelessRouteActiveDidChangeNotification { get; }
}

Просмотреть файл

@ -7045,16 +7045,6 @@ namespace XamCore.UIKit {
[Field ("UIWindowDidResignKeyNotification")]
[Notification]
NSString DidResignKeyNotification { get; }
[NoTV]
[Since (5,0)]
[Field("UIKeyboardWillChangeFrameNotification")]
NSString KeyboardWillChangeFrameNotification { get; }
[NoTV]
[Since (5,0)]
[Field("UIKeyboardDidChangeFrameNotification")]
NSString KeyboardDidChangeFrameNotification { get; }
}
[BaseType (typeof (UIView))]

Просмотреть файл

@ -103,6 +103,83 @@ namespace Introspection {
return false;
}
}
static List<PropertyInfo> properties;
IEnumerable<PropertyInfo> AllProperties ()
{
if (properties != null)
return properties;
properties = new List<PropertyInfo> ();
foreach (Type t in Assembly.GetTypes ()) {
if (Skip (t) || SkipDueToAttribute (t))
continue;
foreach (var p in t.GetProperties (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) {
// looking for properties with getters only
if (p.CanWrite || !p.CanRead)
continue;
if (SkipDueToAttribute (p))
continue;
properties.Add (p);
}
}
return properties;
}
[Test]
#if MONOMAC
[Ignore ("Some API needs fixing - https://jenkins.mono-project.com/job/xamarin-macios-pr-builder/2188/Test_Report/")]
#endif
public void Notifications ()
{
var failed_fields = new List<string> ();
Errors = 0;
int c = 0, n = 0;
foreach (var p in AllProperties ()) {
if (p.PropertyType.FullName != NSStringType)
continue;
var f = p.GetCustomAttribute<FieldAttribute> ();
if (f == null)
continue;
var name = f.SymbolName;
if (!name.EndsWith ("Notification", StringComparison.Ordinal))
continue;
var nested = p.DeclaringType.GetNestedTypes ();
if (nested.Length == 0) {
ReportError (name);
failed_fields.Add (name);
} else {
bool found = false;
foreach (var nt in nested) {
if (nt.Name != "Notifications")
continue;
// look for the associated methods
name = "Observe" + p.Name;
if (name.EndsWith ("Notification", StringComparison.Ordinal))
name = name.Substring (0, name.Length - "Notification".Length);
foreach (var m in nt.GetMethods (BindingFlags.Static | BindingFlags.Public)) {
if (name == m.Name) {
found = true;
break;
}
}
}
if (!found) {
ReportError (name);
failed_fields.Add (name);
}
}
n++;
}
Assert.AreEqual (0, Errors, "{0} errors found in {1} fields validated: {2}", Errors, n, string.Join (", ", failed_fields));
}
[Test]
public void NonNullNSStringFields ()
@ -110,33 +187,18 @@ namespace Introspection {
var failed_fields = new List<string> ();
Errors = 0;
int c = 0, n = 0;
foreach (Type t in Assembly.GetTypes ()) {
if (Skip (t) || SkipDueToAttribute (t))
int n = 0;
foreach (var p in AllProperties ()) {
if (p.PropertyType.FullName != NSStringType)
continue;
if (LogProgress)
Console.WriteLine ("{0}. {1}", c++, t.FullName);
foreach (var p in t.GetProperties (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) {
// looking for properties with getters only
if (p.CanWrite || !p.CanRead)
continue;
if (p.PropertyType.FullName != NSStringType)
continue;
if (SkipDueToAttribute (p))
continue;
string name;
bool result = CheckAgainstNull (p, out name);
if (!result) {
ReportError (name);
failed_fields.Add (name);
}
n++;
string name;
bool result = CheckAgainstNull (p, out name);
if (!result) {
ReportError (name);
failed_fields.Add (name);
}
n++;
}
Assert.AreEqual (0, Errors, "{0} errors found in {1} fields validated: {2}", Errors, n, string.Join (", ", failed_fields));
}
@ -147,39 +209,24 @@ namespace Introspection {
var failed_fields = new List<string> ();
Errors = 0;
int c = 0, n = 0;
foreach (Type t in Assembly.GetTypes ()) {
if (Skip (t) || SkipDueToAttribute (t))
int n = 0;
foreach (var p in AllProperties ()) {
var f = p.GetCustomAttribute<FieldAttribute> ();
if (f == null)
continue;
if (LogProgress)
Console.WriteLine ("{0}. {1}", c++, t.FullName);
string name = f.SymbolName;
if (Skip (name))
continue;
foreach (var p in t.GetProperties (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) {
// looking for properties with getters only
if (p.CanWrite || !p.CanRead)
continue;
if (SkipDueToAttribute (p))
continue;
var f = p.GetCustomAttribute<FieldAttribute> ();
if (f == null)
continue;
string name = f.SymbolName;
if (Skip (name))
continue;
string path = FindLibrary (f.LibraryName);
IntPtr lib = Dlfcn.dlopen (path, 0);
if (Dlfcn.GetIndirect (lib, name) == IntPtr.Zero) {
ReportError ("Could not find the field '{0}' in {1}", name, path);
failed_fields.Add (name);
}
Dlfcn.dlclose (lib);
n++;
string path = FindLibrary (f.LibraryName);
IntPtr lib = Dlfcn.dlopen (path, 0);
if (Dlfcn.GetIndirect (lib, name) == IntPtr.Zero) {
ReportError ("Could not find the field '{0}' in {1}", name, path);
failed_fields.Add (name);
}
Dlfcn.dlclose (lib);
n++;
}
Assert.AreEqual (0, Errors, "{0} errors found in {1} fields validated: {2}", Errors, n, string.Join (", ", failed_fields));
}