diff --git a/tests/cecil-tests/AttributeTest.cs b/tests/cecil-tests/AttributeTest.cs index 84c45a3faf..f3f8b37214 100644 --- a/tests/cecil-tests/AttributeTest.cs +++ b/tests/cecil-tests/AttributeTest.cs @@ -583,5 +583,56 @@ namespace Cecil.Tests { bool IsAvailabilityAttribute (CustomAttribute attribute) => IsSupportedAttribute (attribute) || attribute.AttributeType.Name == "UnsupportedOSPlatformAttribute"; bool IsSupportedAttribute (CustomAttribute attribute) => attribute.AttributeType.Name == "SupportedOSPlatformAttribute"; + + [TestCaseSource (typeof (Helper), nameof (Helper.NetPlatformAssemblyDefinitions))] + public void ModelMustBeProtocol (AssemblyInfo info) + { + // Verify that all types with a [Model] attribute must also have a [Protocol] attribute. + // Exception: If the type in question has a [Register] attribute with IsWrapper = false, then that's OK. + var failures = new HashSet (); + var typesWithModelAttribute = 0; + var typesWithProtocolAttribute = 0; + var assembly = info.Assembly; + + foreach (var type in assembly.EnumerateTypes ()) { + if (!type.HasCustomAttributes) + continue; + + var attributes = type.CustomAttributes; + + if (!attributes.Any (v => v.AttributeType.Is ("Foundation", "ModelAttribute"))) + continue; + typesWithModelAttribute++; + + if (attributes.Any (v => v.AttributeType.Is ("Foundation", "ProtocolAttribute"))) { + typesWithProtocolAttribute++; + continue; + } + + var registerAttribute = attributes.SingleOrDefault (v => v.AttributeType.Is ("Foundation", "RegisterAttribute")); + if (registerAttribute is not null && !GetIsWrapper (registerAttribute)) + continue; + + failures.Add ($"The type {type.FullName} has a [Model] attribute, but no [Protocol] attribute."); + } + + Assert.That (failures, Is.Empty, "Failures"); + Assert.That (typesWithModelAttribute, Is.GreaterThan (0), "No types with the [Model] attribute?"); + Assert.That (typesWithProtocolAttribute, Is.GreaterThan (0), "No types with the [Protocol] attribute?"); + + static bool GetIsWrapper (CustomAttribute attrib) + { + // .ctor (string name, bool isWrapper) + if (attrib.ConstructorArguments.Count == 2) + return (bool) attrib.ConstructorArguments [1].Value; + + // public bool IsWrapper { get; set; } + foreach (var field in attrib.Fields) { + if (field.Name == "IsWrapper") + return (bool) field.Argument.Value; + } + return false; + } + } } } diff --git a/tests/monotouch-test/Foundation/ProtocolAttributeTest.cs b/tests/monotouch-test/Foundation/ProtocolAttributeTest.cs deleted file mode 100644 index f814267f66..0000000000 --- a/tests/monotouch-test/Foundation/ProtocolAttributeTest.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -// Unit tests for ProtocolAttribute (yeah, really!) -// -// Authors: -// Rolf Bjarne Kvinge -// -// Copyright 2013 Xamarin Inc. All rights reserved. -// - -using System; -using Foundation; -using ObjCRuntime; -using NUnit.Framework; - -namespace MonoTouchFixtures.Foundation { - - [TestFixture] - [Preserve (AllMembers = true)] - public class ProtocolAttributeTest { - - [Test] - public void ModelMustBeProtocol () - { - int count = 0; - - // - // Note that [Model], but no [Protocol] is not a universal truth (so it's - // not enforced in the generator), but it should be true for monotouch.dll. - // - - foreach (var type in typeof (NSObject).Assembly.GetTypes ()) { - if (!type.IsSubclassOf (typeof (NSObject))) - continue; - - var register = (RegisterAttribute) Attribute.GetCustomAttribute (type, typeof (RegisterAttribute), false); - if (register is not null && !register.IsWrapper) - continue; - - if (Attribute.GetCustomAttribute (type, typeof (ModelAttribute), false) is null) - continue; - - if (Attribute.GetCustomAttribute (type, typeof (ProtocolAttribute), false) is null) { - Console.WriteLine ("{0} must have a [Protocol] attribute if it has a [Model] attribute", type.FullName); - count++; - } - } - - if (count > 0) - Assert.Fail ("Found {0} types with a [Model] attribute (and no [Register(false)] attribute signalling that they're not wrapper types), but without a [Protocol] attribute.", count); - } - } -}