2016-05-05 03:14:32 +03:00
|
|
|
//
|
|
|
|
// Test the generated API for all CoreImage filters
|
|
|
|
//
|
|
|
|
// Authors:
|
|
|
|
// Sebastien Pouliot <sebastien@xamarin.com>
|
|
|
|
//
|
|
|
|
// Copyright 2013, 2015 Xamarin Inc.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
|
|
|
|
#if !__WATCHOS__
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Reflection;
|
2019-10-16 16:16:32 +03:00
|
|
|
using System.Text;
|
2016-05-05 03:14:32 +03:00
|
|
|
|
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
|
|
using CoreImage;
|
|
|
|
using Foundation;
|
|
|
|
using ObjCRuntime;
|
|
|
|
#if !MONOMAC
|
|
|
|
using UIKit;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace Introspection {
|
|
|
|
|
|
|
|
[TestFixture]
|
|
|
|
// we want the tests to be available because we use the linker
|
|
|
|
[Preserve (AllMembers = true)]
|
|
|
|
public abstract class ApiCoreImageFiltersTest : ApiBaseTest {
|
|
|
|
|
|
|
|
static Type CIFilterType = typeof (CIFilter);
|
|
|
|
|
2020-06-26 21:02:44 +03:00
|
|
|
#if false
|
2019-06-19 15:26:40 +03:00
|
|
|
static TextWriter BindingOutput;
|
|
|
|
#else
|
|
|
|
static TextWriter BindingOutput = Console.Out;
|
|
|
|
#endif
|
|
|
|
|
2016-05-05 03:14:32 +03:00
|
|
|
protected virtual bool Skip (Type type)
|
|
|
|
{
|
|
|
|
return Skip (type.Name) || SkipDueToAttribute (type);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual bool Skip (string nativeName)
|
|
|
|
{
|
|
|
|
switch (nativeName) {
|
|
|
|
// Both reported in radar #21548819
|
|
|
|
// NSUnknownKeyException [<CIDepthOfField 0x158586970> valueForUndefinedKey:]: this class is not key value coding-compliant for the key inputPoint2.
|
|
|
|
case "CIDepthOfField":
|
|
|
|
return true;
|
2018-07-27 15:27:23 +03:00
|
|
|
// Apple does **not** document filters as API (like we do)
|
|
|
|
// uncomment calls to `GenerateBinding` to use introspection code to generate the skeleton binding code and complete it
|
|
|
|
// e.g. picking better types like `bool` instead of `NSNumber'
|
2016-05-05 03:14:32 +03:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
// this test checks that all native filters have a managed peer, i.e. against missing filters
|
|
|
|
public void CheckNativeFilters ()
|
|
|
|
{
|
2020-10-15 03:06:20 +03:00
|
|
|
Errors = 0;
|
2016-05-05 03:14:32 +03:00
|
|
|
List<string> filters = new List<string> ();
|
|
|
|
int n = 0;
|
|
|
|
string qname = CIFilterType.AssemblyQualifiedName;
|
|
|
|
// that will give us only the list of filters supported by the executing version of iOS
|
|
|
|
foreach (var filter_name in CIFilter.FilterNamesInCategories (null)) {
|
|
|
|
if (Skip (filter_name))
|
|
|
|
continue;
|
|
|
|
string type_name = qname.Replace ("CIFilter", filter_name);
|
|
|
|
if (Type.GetType (type_name, false, true) == null) {
|
|
|
|
filters.Add (filter_name);
|
2019-06-19 15:26:40 +03:00
|
|
|
if (BindingOutput != null)
|
|
|
|
GenerateBinding (CIFilter.FromName (filter_name), BindingOutput);
|
2016-05-05 03:14:32 +03:00
|
|
|
}
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
Assert.That (filters.Count, Is.EqualTo (0), "{0} native filters missing: {1}", filters.Count, String.Join (", ", filters));
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
// this test checks that all managed filters have a native peer, i.e. against extra filters
|
|
|
|
public void CheckManagedFilters ()
|
|
|
|
{
|
2020-10-15 03:06:20 +03:00
|
|
|
Errors = 0;
|
2018-06-09 04:45:24 +03:00
|
|
|
ContinueOnFailure = true;
|
2016-05-05 03:14:32 +03:00
|
|
|
List<string> filters = new List<string> (CIFilter.FilterNamesInCategories (null));
|
2017-11-17 00:38:14 +03:00
|
|
|
var superFilters = new List<string> ();
|
2016-05-05 03:14:32 +03:00
|
|
|
var nspace = CIFilterType.Namespace;
|
|
|
|
var types = CIFilterType.Assembly.GetTypes ();
|
|
|
|
foreach (Type t in types) {
|
|
|
|
if (t.Namespace != nspace)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (t.IsAbstract || !CIFilterType.IsAssignableFrom (t))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// we need to skip the filters that are not supported by the executing version of iOS
|
|
|
|
if (Skip (t))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var ctor = t.GetConstructor (Type.EmptyTypes);
|
|
|
|
if ((ctor == null) || ctor.IsAbstract)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
NSObject obj = ctor.Invoke (null) as NSObject;
|
|
|
|
#if false
|
|
|
|
// check base type - we might have our own base type or different names, so it's debug only (not failure)
|
|
|
|
var super = new Class (obj.Class.SuperClass).Name;
|
|
|
|
var bt = t.BaseType.Name;
|
2017-11-17 00:38:14 +03:00
|
|
|
if ((super != bt) && (bt == "CIFilter")) { // check if we should (like Apple) use a non-default base type for filters
|
2016-05-05 03:14:32 +03:00
|
|
|
Console.WriteLine ("[WARN] {0}.SuperClass == {1} (native) and {2} managed", t.Name, super, bt);
|
2017-11-17 00:38:14 +03:00
|
|
|
if (!superFilters.Contains (super)) {
|
|
|
|
superFilters.Add (super);
|
|
|
|
Console.WriteLine ("[GENERATED] {0}", super);
|
2019-06-19 15:26:40 +03:00
|
|
|
GenerateBinding (CIFilter.FromName (super), BindingOutput);
|
2017-11-17 00:38:14 +03:00
|
|
|
}
|
|
|
|
}
|
2016-05-05 03:14:32 +03:00
|
|
|
#endif
|
|
|
|
int result = filters.RemoveAll (s => StringComparer.OrdinalIgnoreCase.Compare (t.Name, s) == 0);
|
2018-06-09 04:45:24 +03:00
|
|
|
if ((result == 0) && !Skip (t))
|
|
|
|
ReportError ($"Managed {t.Name} was not part of the native filter list");
|
2016-05-05 03:14:32 +03:00
|
|
|
}
|
|
|
|
// in case it's a buggy filter we need to try to remove it from the list too
|
|
|
|
for (int i = filters.Count - 1; i >= 0; i--) {
|
|
|
|
if (Skip (filters [i]))
|
|
|
|
filters.RemoveAt (i);
|
|
|
|
}
|
|
|
|
Assert.That (filters.Count, Is.EqualTo (0), "Managed filters not found for {0}", String.Join (", ", filters));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GenerateBinding (NSObject filter, TextWriter writer)
|
|
|
|
{
|
|
|
|
NSObject value;
|
|
|
|
var attributes = (filter as CIFilter).Attributes;
|
|
|
|
|
|
|
|
writer.WriteLine ("[CoreImageFilter]");
|
|
|
|
|
|
|
|
if (!attributes.TryGetValue ((NSString)"CIAttributeFilterAvailable_iOS", out value)) {
|
|
|
|
writer.WriteLine ("[NoiOS]");
|
|
|
|
} else {
|
|
|
|
var v = value.ToString ();
|
|
|
|
// in the (quite common) case we get "5" for iOS 5.0
|
|
|
|
if (v.IndexOf ('.') == -1)
|
|
|
|
v += ".0";
|
|
|
|
var ios = Version.Parse (v);
|
|
|
|
// we only document availability for iOS 6+
|
|
|
|
if (ios.Major > 5)
|
|
|
|
writer.WriteLine ("[iOS ({0},{1})]", ios.Major, ios.Minor);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!attributes.TryGetValue ((NSString)"CIAttributeFilterAvailable_Mac", out value)) {
|
|
|
|
writer.WriteLine ("[NoMac]");
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
var mac = Version.Parse (value.ToString ());
|
|
|
|
// we only document availability for 10.7+
|
|
|
|
if (mac.Minor > 6)
|
|
|
|
writer.WriteLine ("[Mac ({0},{1})]", mac.Major, mac.Minor);
|
|
|
|
}
|
|
|
|
catch (FormatException) {
|
|
|
|
// 10.? is not a valid version - we'll assume it was added a long time ago (in a galaxy far away)
|
|
|
|
writer.WriteLine ("// incorrect version string for OSX: '{0}' Double-check documentation", value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
writer.WriteLine ("[BaseType (typeof (CIFilter))]");
|
|
|
|
var fname = attributes [(NSString)"CIAttributeFilterName"].ToString ();
|
|
|
|
writer.WriteLine ("interface {0} {{", fname);
|
|
|
|
foreach (var k in attributes.Keys) {
|
|
|
|
var key = k.ToString ();
|
|
|
|
if (key.StartsWith ("CIAttribute", StringComparison.Ordinal))
|
|
|
|
continue;
|
|
|
|
// CIFilter defines it for all filters
|
|
|
|
if (key == "inputImage")
|
|
|
|
continue;
|
|
|
|
|
|
|
|
writer.WriteLine ();
|
|
|
|
var dict = attributes [k] as NSDictionary;
|
|
|
|
var type = dict [(NSString) "CIAttributeClass"];
|
2019-06-19 15:26:40 +03:00
|
|
|
writer.WriteLine ($"\t[CoreImageFilterProperty (\"{key}\")]");
|
2016-05-05 03:14:32 +03:00
|
|
|
|
|
|
|
// by default we drop the "input" prefix, but keep the "output" prefix to avoid confusion
|
|
|
|
if (key.StartsWith ("input", StringComparison.Ordinal))
|
|
|
|
key = Char.ToUpperInvariant (key [5]) + key.Substring (6);
|
2019-06-19 15:26:40 +03:00
|
|
|
|
|
|
|
writer.WriteLine ("\t/* REMOVE-ME");
|
|
|
|
writer.WriteLine (dict);
|
|
|
|
writer.WriteLine ("\t*/");
|
|
|
|
writer.WriteLine ($"\t{type} {key} {{ get; set; }}");
|
2016-05-05 03:14:32 +03:00
|
|
|
}
|
|
|
|
writer.WriteLine ("}");
|
|
|
|
writer.WriteLine ();
|
2019-06-19 15:26:40 +03:00
|
|
|
writer.Flush ();
|
2016-05-05 03:14:32 +03:00
|
|
|
}
|
2019-10-16 16:16:32 +03:00
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void Protocols ()
|
|
|
|
{
|
2020-10-15 03:06:20 +03:00
|
|
|
Errors = 0;
|
2019-10-16 16:16:32 +03:00
|
|
|
var to_confirm_manually = new StringBuilder ();
|
|
|
|
ContinueOnFailure = true;
|
|
|
|
var nspace = CIFilterType.Namespace;
|
|
|
|
var types = CIFilterType.Assembly.GetTypes ();
|
|
|
|
foreach (Type t in types) {
|
|
|
|
if (t.Namespace != nspace)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// e.g. FooProtocolWrapper
|
|
|
|
if (!t.IsPublic)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (t.Name) {
|
|
|
|
// we are interested in subclasses (real) filters
|
|
|
|
case "CIFilter":
|
|
|
|
continue;
|
|
|
|
// no protocol has been added (yet?) you can confirm with `grep` that it does not report anything in the terminal
|
|
|
|
case "CIAdditionCompositing":
|
|
|
|
case "CIAreaAverage":
|
|
|
|
case "CIAreaHistogram":
|
|
|
|
case "CIAreaMaximum":
|
|
|
|
case "CIAreaMaximumAlpha":
|
|
|
|
case "CIAreaMinimum":
|
|
|
|
case "CIAreaMinimumAlpha":
|
|
|
|
case "CIAreaMinMax":
|
|
|
|
case "CIAreaMinMaxRed":
|
|
|
|
case "CIBlendFilter":
|
|
|
|
case "CIBumpDistortion":
|
|
|
|
case "CIBumpDistortionLinear":
|
|
|
|
case "CICameraCalibrationLensCorrection":
|
|
|
|
case "CICircleSplashDistortion":
|
|
|
|
case "CICircularWrap":
|
|
|
|
case "CIClamp":
|
|
|
|
case "CICodeGenerator":
|
|
|
|
case "CIColorBlendMode":
|
|
|
|
case "CIColorBurnBlendMode":
|
|
|
|
case "CIColorDodgeBlendMode":
|
|
|
|
case "CIColumnAverage":
|
|
|
|
case "CICompositingFilter":
|
|
|
|
case "CIConstantColorGenerator":
|
|
|
|
case "CIConvolution3X3":
|
|
|
|
case "CIConvolution5X5":
|
|
|
|
case "CIConvolution7X7":
|
|
|
|
case "CIConvolution9Horizontal":
|
|
|
|
case "CIConvolution9Vertical":
|
|
|
|
case "CIConvolutionCore":
|
|
|
|
case "CICoreMLModelFilter":
|
|
|
|
case "CICrop":
|
|
|
|
case "CIDarkenBlendMode":
|
|
|
|
case "CIDepthBlurEffect":
|
|
|
|
case "CIDepthDisparityConverter":
|
|
|
|
case "CIDifferenceBlendMode":
|
|
|
|
case "CIDisplacementDistortion":
|
|
|
|
case "CIDistortionFilter":
|
|
|
|
case "CIDivideBlendMode":
|
|
|
|
case "CIDroste":
|
|
|
|
case "CIExclusionBlendMode":
|
|
|
|
case "CIFaceBalance":
|
|
|
|
case "CIGlassDistortion":
|
|
|
|
case "CIGlassLozenge":
|
|
|
|
case "CIGuidedFilter":
|
|
|
|
case "CIHardLightBlendMode":
|
|
|
|
case "CIHistogramDisplayFilter":
|
|
|
|
case "CIHoleDistortion":
|
|
|
|
case "CIHueBlendMode":
|
|
|
|
case "CIImageGenerator":
|
|
|
|
case "CIKeystoneCorrection":
|
|
|
|
case "CIKMeans":
|
|
|
|
case "CILightenBlendMode":
|
|
|
|
case "CILightTunnel":
|
|
|
|
case "CILinearBlur":
|
|
|
|
case "CILinearBurnBlendMode":
|
|
|
|
case "CILinearDodgeBlendMode":
|
|
|
|
case "CILuminosityBlendMode":
|
|
|
|
case "CIMaximumCompositing":
|
|
|
|
case "CIMinimumCompositing":
|
|
|
|
case "CIMorphology":
|
|
|
|
case "CIMorphologyRectangle":
|
|
|
|
case "CIMultiplyBlendMode":
|
|
|
|
case "CIMultiplyCompositing":
|
|
|
|
case "CINinePartStretched":
|
|
|
|
case "CINinePartTiled":
|
|
|
|
case "CIOverlayBlendMode":
|
|
|
|
case "CIPinchDistortion":
|
|
|
|
case "CIPinLightBlendMode":
|
|
|
|
case "CIReductionFilter":
|
|
|
|
case "CIRowAverage":
|
|
|
|
case "CISampleNearest":
|
|
|
|
case "CISaturationBlendMode":
|
|
|
|
case "CIScreenBlendMode":
|
|
|
|
case "CIScreenFilter":
|
|
|
|
case "CISoftLightBlendMode":
|
|
|
|
case "CISourceAtopCompositing":
|
|
|
|
case "CISourceInCompositing":
|
|
|
|
case "CISourceOutCompositing":
|
|
|
|
case "CISourceOverCompositing":
|
|
|
|
case "CIStretchCrop":
|
|
|
|
case "CISubtractBlendMode":
|
|
|
|
case "CITileFilter":
|
|
|
|
case "CITorusLensDistortion":
|
|
|
|
case "CITwirlDistortion":
|
|
|
|
case "CIVortexDistortion":
|
|
|
|
// this list is likely to change with newer Xcode - uncomment if you want to the script to check the list
|
|
|
|
//to_confirm_manually.AppendLine ($"grep {t.Name} `xcode-select -p`/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/CoreImage.framework/Headers/*.h");
|
|
|
|
// since xtro will report the missing protocols this is a 2nd layer of safety :)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool assign = typeof (ICIFilterProtocol).IsAssignableFrom (t);
|
|
|
|
bool suffix = t.Name.EndsWith ("Protocol", StringComparison.Ordinal);
|
|
|
|
|
|
|
|
if (t.IsInterface) {
|
|
|
|
if (assign) {
|
|
|
|
// check that `IFooProtocol` has a [Protocol (Name = "Foo")] attribute
|
|
|
|
var ca = t.GetCustomAttribute<ProtocolAttribute> (false);
|
|
|
|
if (ca == null) {
|
|
|
|
ReportError ($"Managed {t.Name} should have a '[Protocol (Name=\"{t.Name.Replace ("Protocol", "")}\")]' attribute");
|
|
|
|
}
|
|
|
|
// check that the managed name ends with Protocol, so we can have the _normal_ name to be a concrete type (like our historic, strongly typed filters)
|
|
|
|
if (!suffix) {
|
|
|
|
ReportError ($"Managed {t.Name} should have a 'Protocol' suffix");
|
|
|
|
}
|
|
|
|
} else if (suffix) {
|
|
|
|
ReportError ($"Managed {t.Name} should implement 'ICIFilterProtocol' interface.");
|
|
|
|
}
|
|
|
|
} else if (suffix) {
|
|
|
|
ReportError ($"Managed {t.Name} should be an interface since it represent a protocol");
|
|
|
|
} else if (assign) {
|
|
|
|
// all CIFilter should map to a `ICI*Protocol` interface / protocol
|
|
|
|
bool found = false;
|
|
|
|
foreach (var inft in t.GetInterfaces ()) {
|
|
|
|
if (inft.Namespace == nspace && inft.Name.EndsWith ("Protocol", StringComparison.Ordinal)) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
ReportError ($"Managed CIFilter '{t.Name}' does not conform to any CoreImage filter protocol.");
|
|
|
|
} else if (CIFilterType.IsAssignableFrom (t)) {
|
|
|
|
// missing ICIFilterProtocol
|
|
|
|
to_confirm_manually.AppendLine ($"grep \"protocol {t.Name} \" `xcode-select -p`/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/CoreImage.framework/Headers/*.h");
|
|
|
|
ReportError ($"Managed CIFilter '{t.Name}' does not conform to 'ICIFilterProtocol' protocol. Confirm with generated `grep` script on console.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (to_confirm_manually.Length > 0) {
|
|
|
|
Console.WriteLine (to_confirm_manually);
|
|
|
|
}
|
|
|
|
Assert.AreEqual (0, Errors, "{0} potential errors found{1}", Errors, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString () + "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void Keys ()
|
|
|
|
{
|
2020-10-15 03:06:20 +03:00
|
|
|
Errors = 0;
|
2019-10-16 16:16:32 +03:00
|
|
|
ContinueOnFailure = true;
|
|
|
|
var nspace = CIFilterType.Namespace;
|
|
|
|
var types = CIFilterType.Assembly.GetTypes ();
|
|
|
|
foreach (Type t in types) {
|
|
|
|
if (t.Namespace != nspace)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (t.IsAbstract || !CIFilterType.IsAssignableFrom (t))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// we need to skip the filters that are not supported by the executing version of iOS
|
|
|
|
if (Skip (t))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var ctor = t.GetConstructor (Type.EmptyTypes);
|
|
|
|
if ((ctor == null) || ctor.IsAbstract)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CIFilter f = ctor.Invoke (null) as CIFilter;
|
|
|
|
|
|
|
|
// first check that every property can be mapped to an input key - except if it starts with "Output"
|
|
|
|
foreach (var p in t.GetProperties (BindingFlags.Public | BindingFlags.Instance)) {
|
|
|
|
var pt = p.DeclaringType;
|
|
|
|
if (!CIFilterType.IsAssignableFrom (pt) || (pt == CIFilterType))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (SkipDueToAttribute (p))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var getter = p.GetGetMethod ();
|
|
|
|
var ea = getter.GetCustomAttribute<ExportAttribute> (false);
|
|
|
|
// only properties coming (inlined) from protocols have an [Export] attribute
|
|
|
|
if (ea == null)
|
|
|
|
continue;
|
|
|
|
var key = ea.Selector;
|
|
|
|
// 'output' is always explicit
|
|
|
|
if (key.StartsWith ("output", StringComparison.Ordinal)) {
|
|
|
|
if (Array.IndexOf (f.OutputKeys, key) < 0) {
|
|
|
|
ReportError ($"{t.Name}: Property `{p.Name}` mapped to key `{key}` is not part of `OutputKeys`.");
|
|
|
|
//GenerateBinding (f, Console.Out);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// special cases (protocol names are better)
|
|
|
|
switch (t.Name) {
|
|
|
|
case "CIBicubicScaleTransform":
|
|
|
|
switch (key) {
|
|
|
|
case "parameterB":
|
|
|
|
key = "inputB";
|
|
|
|
break;
|
|
|
|
case "parameterC":
|
|
|
|
key = "inputC";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "CICmykHalftone":
|
|
|
|
switch (key) {
|
|
|
|
case "grayComponentReplacement":
|
|
|
|
key = "inputGCR";
|
|
|
|
break;
|
|
|
|
case "underColorRemoval":
|
|
|
|
key = "inputUCR";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-07-10 15:56:23 +03:00
|
|
|
case "CIGlassDistortion":
|
|
|
|
switch (key) {
|
|
|
|
case "textureImage":
|
|
|
|
key = "texture";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2019-10-16 16:16:32 +03:00
|
|
|
}
|
|
|
|
// 'input' is implied (generally) and explicit (in a few cases)
|
|
|
|
if (!key.StartsWith ("input", StringComparison.Ordinal))
|
|
|
|
key = "input" + Char.ToUpperInvariant (key [0]) + key.Substring (1);
|
|
|
|
|
|
|
|
if (Array.IndexOf (f.InputKeys, key) < 0) {
|
|
|
|
ReportError ($"{t.Name}: Property `{p.Name}` mapped to key `{key}` is not part of `InputKeys`.");
|
|
|
|
//GenerateBinding (f, Console.Out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// second check that every input key is mapped to an property
|
|
|
|
foreach (var key in f.InputKeys) {
|
|
|
|
string cap = Char.ToUpperInvariant (key [0]) + key.Substring (1);
|
|
|
|
// special cases (protocol names are better)
|
|
|
|
switch (t.Name) {
|
|
|
|
case "CICmykHalftone":
|
|
|
|
switch (key) {
|
|
|
|
case "inputGCR":
|
|
|
|
cap = "GrayComponentReplacement";
|
|
|
|
break;
|
|
|
|
case "inputUCR":
|
|
|
|
cap = "UnderColorRemoval";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// IgnoreCase because there are acronyms (more than 2 letters) that naming convention force us to change
|
|
|
|
var pi = t.GetProperty (cap, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
|
|
|
|
if (pi == null) {
|
|
|
|
// 2nd chance: some, but not all, property are prefixed by `Input`
|
|
|
|
if (key.StartsWith ("input", StringComparison.Ordinal)) {
|
|
|
|
cap = Char.ToUpperInvariant (key [5]) + key.Substring (6);
|
|
|
|
pi = t.GetProperty (cap, BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pi == null) {
|
|
|
|
ReportError ($"{t.Name}: Input Key `{key}` is NOT mapped to a `{cap}` property.");
|
|
|
|
//GenerateBinding (f, Console.Out);
|
|
|
|
} else if (pi.GetSetMethod () == null)
|
|
|
|
ReportError ($"{t.Name}: Property `{pi.Name}` MUST have a setter.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// third check that every output key is mapped to an property
|
|
|
|
foreach (var key in f.OutputKeys) {
|
|
|
|
// special cases
|
|
|
|
switch (t.Name) {
|
|
|
|
case "CIKeystoneCorrectionCombined":
|
|
|
|
case "CIKeystoneCorrectionHorizontal":
|
|
|
|
case "CIKeystoneCorrectionVertical":
|
|
|
|
switch (key) {
|
|
|
|
case "outputRotationFilter":
|
|
|
|
continue; // lack of documentation about the returned type
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "CILanczosScaleTransform":
|
|
|
|
switch (key) {
|
|
|
|
// ref: https://github.com/xamarin/xamarin-macios/issues/7209
|
|
|
|
case "outputImageNewScaleX:scaleY:":
|
|
|
|
case "outputImageOldScaleX:scaleY:":
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "CIDiscBlur":
|
|
|
|
switch (key) {
|
|
|
|
// existed in iOS 10.3 but not in iOS 13 - we're not adding them
|
|
|
|
case "outputImageOriginal":
|
|
|
|
case "outputImageEnhanced":
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
[CoreImage] Fix a couple of test/availability issues. (#7259)
Fixes this on macOS 10.9:
1) ApiCtorInitTest.DefaultCtorAllowed (Introspection.MacApiCtorInitTest.ApiCtorInitTest.DefaultCtorAllowed)
1 potential errors found in 860 default ctor validated:
CoreImage.CIMaskedVariableBlur : Handle
Expected: 0
But was: 1
at Introspection.ApiCtorInitTest.DefaultCtorAllowed () [0x0019b] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/introspection/ApiCtorInitTest.cs:295
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:395
2) ApiCoreImageFiltersTest.Keys (Introspection.MacCoreImageFiltersTest.ApiCoreImageFiltersTest.Keys)
System.ArgumentNullException : Value cannot be null.
Parameter name: array
at System.Array.IndexOf[T] (T[] array, T value) [0x0000e] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/external/corert/src/System.Private.CoreLib/src/System/Array.cs:666
at Introspection.ApiCoreImageFiltersTest.Keys () [0x002b7] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/introspection/ApiCoreImageFiltersTest.cs:445
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:395
3) ApiCoreImageFiltersTest.Protocols (Introspection.MacCoreImageFiltersTest.ApiCoreImageFiltersTest.Protocols)
1 potential errors found:
Managed CIMaskedVariableBlur was not part of the native filter list
Expected: 0
But was: 1
at Introspection.ApiCoreImageFiltersTest.Protocols () [0x0104e] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/introspection/ApiCoreImageFiltersTest.cs:370
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:395
And this on macOS 10.10:
1) ApiCoreImageFiltersTest.Keys (Introspection.MacCoreImageFiltersTest.ApiCoreImageFiltersTest.Keys)
1 potential errors found:
CICode128BarcodeGenerator: Property `BarcodeHeight` mapped to key `inputBarcodeHeight` is not part of `InputKeys`.
Expected: 0
But was: 1
at Introspection.ApiCoreImageFiltersTest.Keys () [0x006b1] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/introspection/ApiCoreImageFiltersTest.cs:524
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:395
2) ApiCoreImageFiltersTest.Protocols (Introspection.MacCoreImageFiltersTest.ApiCoreImageFiltersTest.Protocols)
1 potential errors found:
CICode128BarcodeGenerator: Property `BarcodeHeight` mapped to key `inputBarcodeHeight` is not part of `InputKeys`.
Expected: 0
But was: 1
at Introspection.ApiCoreImageFiltersTest.Protocols () [0x0104e] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/introspection/ApiCoreImageFiltersTest.cs:370
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:395
And this on macOS 11.11:
1) ApiCoreImageFiltersTest.Keys (Introspection.MacCoreImageFiltersTest.ApiCoreImageFiltersTest.Keys)
2 potential errors found:
CICode128BarcodeGenerator: Property `BarcodeHeight` mapped to key `inputBarcodeHeight` is not part of `InputKeys`.
CIGaussianBlur: Output Key `outputImageV1` is NOT mapped to a `OutputImageV1` property.
Expected: 0
But was: 2
at Introspection.ApiCoreImageFiltersTest.Keys () [0x006b1] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/introspection/ApiCoreImageFiltersTest.cs:524
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:395
2) ApiCoreImageFiltersTest.Protocols (Introspection.MacCoreImageFiltersTest.ApiCoreImageFiltersTest.Protocols)
2 potential errors found:
CICode128BarcodeGenerator: Property `BarcodeHeight` mapped to key `inputBarcodeHeight` is not part of `InputKeys`.
CIGaussianBlur: Output Key `outputImageV1` is NOT mapped to a `OutputImageV1` property.
Expected: 0
But was: 2
at Introspection.ApiCoreImageFiltersTest.Protocols () [0x0104e] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/introspection/ApiCoreImageFiltersTest.cs:370
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:395
2019-10-18 23:42:12 +03:00
|
|
|
case "CIGaussianBlur":
|
|
|
|
switch (key) {
|
|
|
|
case "outputImageV1":
|
|
|
|
// existed briefly in macOS 10.11, but neither before nor after.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
2020-06-26 21:02:44 +03:00
|
|
|
case "CIAreaAverage":
|
|
|
|
case "CIAreaHistogram":
|
|
|
|
case "CIAreaMinMax":
|
|
|
|
switch (key) {
|
|
|
|
case "outputImageMPS":
|
|
|
|
case "outputImageMPS:":
|
|
|
|
case "outputImageNonMPS:":
|
|
|
|
// no doc for argument
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
2019-10-16 16:16:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var cap = Char.ToUpperInvariant (key [0]) + key.Substring (1);
|
|
|
|
// IgnoreCase because there are acronyms (more than 2 letters) that naming convention force us to change
|
|
|
|
var po = t.GetProperty (cap, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
|
|
|
|
if (po == null) {
|
|
|
|
ReportError ($"{t.Name}: Output Key `{key}` is NOT mapped to a `{cap}` property.");
|
|
|
|
//GenerateBinding (f, Console.Out);
|
|
|
|
} else if (po.GetSetMethod () != null)
|
|
|
|
ReportError ($"{t.Name}: Property `{po.Name}` should NOT have a setter.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Assert.AreEqual (0, Errors, "{0} potential errors found{1}", Errors, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString () + "\n");
|
|
|
|
}
|
2016-05-05 03:14:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // !__WATCHOS__
|