xamarin-macios/tests/cecil-tests/ApiTest.cs

164 строки
5.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using NUnit.Framework;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Xamarin.Tests;
using Xamarin.Utils;
#nullable enable
namespace Cecil.Tests {
[TestFixture]
public partial class ApiTest {
[TestCaseSource (typeof (Helper), nameof (Helper.PlatformAssemblyDefinitions))]
[TestCaseSource (typeof (Helper), nameof (Helper.NetPlatformAssemblyDefinitions))]
public void ARConfiguration_GetSupportedVideoFormats (AssemblyInfo info)
{
// all subclasses of ARConfiguration must (re)export 'GetSupportedVideoFormats'
var assembly = info.Assembly;
List<string>? failures = null;
if (!assembly.EnumerateTypes ((type) => type.Is ("ARKit", "ARConfiguration")).Any ())
Assert.Ignore (); // This assembly doesn't contain ARKit.ARConfiguration
var subclasses = assembly.EnumerateTypes ((type) => !type.Is ("ARKit", "ARConfiguration") && type.IsSubclassOf ("ARKit", "ARConfiguration"));
Assert.That (subclasses, Is.Not.Empty, "At least some subclasses");
foreach (var type in subclasses) {
var method = type.Methods.SingleOrDefault (m => m.Name == "GetSupportedVideoFormats" && m.IsPublic && m.IsStatic && !m.HasParameters);
if (method is null)
AddFailure (ref failures, $"The type {type.FullName} does not implement the method GetSupportedVideoFormats.");
}
Assert.That (failures, Is.Null.Or.Empty, "All subclasses from ARConfiguration must explicitly implement GetSupportedVideoFormats.");
}
static void AddFailure (ref List<string>? failures, string failure)
{
if (failures is null)
failures = new List<string> ();
failures.Add (failure);
Console.WriteLine (failure);
}
// Capitalization rules:
// * All types, methods, properties, fields, events must start with an upper-cased letter.
// * All parameters must start with a lower-cased letter
[Test]
public void MustStartWithCapitalLetter ()
{
Configuration.IgnoreIfAnyIgnoredPlatforms ();
var failures = new Dictionary<string, (string Message, string Location)> ();
foreach (var info in Helper.NetPlatformImplementationAssemblyDefinitions) {
var assembly = info.Assembly;
foreach (var member in assembly.EnumeratePublicMembers ()) {
// Presumably obsolete members have been obsoleted for a reason, so assume there's a correctly capitalized version.
if (((ICustomAttributeProvider) member).IsObsolete ())
continue;
if (member is MethodDefinition method) {
// Check parameter names
foreach (var param in method.Parameters) {
if (param.Index == 0 && method.IsExtensionMethod ())
continue;
if (!char.IsLower (param.Name [0])) {
var msg = $"The parameter '{param.Name}' in the method '{method.FullName}' has incorrect capitalization: first letter is not lower case.";
failures [msg] = new (msg, method.RenderLocation ());
}
}
// skip constructors
if (method.IsConstructor)
continue;
// skip property accessors
if (method.IsPropertyAccessor ())
continue;
// skip event methods
if (method.IsEventMethod ())
continue;
// skip operators
if (method.IsOperator ())
continue;
} else if (member is FieldDefinition field) {
if (field.Name == "value__" && !field.IsStatic && field.DeclaringType.IsEnum)
continue;
}
if (!char.IsUpper (member.Name [0]) && !IsAcceptableCapitalization (member)) {
var msg = $"The {member.GetType ().Name.Replace ("Definition", "").ToLower ()} '{member.FullName}' has incorrect capitalization: first letter is not upper case.";
failures [msg] = new (msg, member.RenderLocation ());
}
}
}
Helper.AssertFailures (failures, knownFailuresMustStartWithCapitalizationLetter, nameof (knownFailuresMustStartWithCapitalizationLetter), "Incorrect capitalization", (v) => $"{v.Location}: {v.Message}");
}
// The difference between this and the known failures is that these aren't failures (that should be fixed), they're exceptions we've deemed acceptable (and shouldn't be fixed).
bool IsAcceptableCapitalization (MemberReference mr)
{
if (mr is FieldDefinition field) {
switch (field.DeclaringType.FullName) {
case "Metal.MTLFeatureSet":
if (field.Name.StartsWith ("iOS_", StringComparison.Ordinal))
return true;
if (field.Name.StartsWith ("macOS_", StringComparison.Ordinal))
return true;
if (field.Name.StartsWith ("tvOS_", StringComparison.Ordinal))
return true;
break;
case "Metal.MTLGpuFamily":
if (field.Name.StartsWith ("iOSMac", StringComparison.Ordinal))
return true;
break;
}
} else if (mr is PropertyDefinition property) {
switch (property.DeclaringType.FullName) {
case "AVFoundation.AVMetadata":
if (property.Name.StartsWith ("iTunes", StringComparison.Ordinal))
return true;
break;
}
}
return false;
}
[Test]
public void InvalidStrings ()
{
Configuration.IgnoreIfAnyIgnoredPlatforms ();
var invalidStrings = new [] {
new { Find = "URL", Replacement = "Url" }
};
var failures = new Dictionary<string, (string Message, string Location)> ();
foreach (var info in Helper.NetPlatformImplementationAssemblyDefinitions) {
var assembly = info.Assembly;
foreach (var member in assembly.EnumeratePublicMembers ()) {
foreach (var term in invalidStrings) {
if (member.Name.Contains (term.Find)) {
var msg = $"The {member.GetType ().Name.Replace ("Definition", "").ToLower ()} '{member.FullName}' has an invalid term '{term.Find}'. Replace with: '{term.Replacement}'.";
failures [msg] = new (msg, member.RenderLocation ());
}
}
}
}
Helper.AssertFailures (failures, knownFailuresInvalidStrings, nameof (knownFailuresInvalidStrings), "In the file tests/cecil-tests/ApiTest.cs, read the guide carefully.", (v) => $"{v.Location}: {v.Message}");
}
}
}