CSInterface CompileProtocol(ProtocolDeclaration proto, CSUsingPackages use)
        {
            var iface = new CSInterface(CSVisibility.Public, proto.Name);

            kProtocolAttribute.AttachBefore(iface);
            var filteredInheritance = proto.Inheritance.FindAll(inh => !TypeSpecIsAnyOrAnyObject(inh.InheritedTypeSpec));

            iface.Inheritance.AddRange(filteredInheritance.Select(inh => {
                var netIface = typeMapper.GetDotNetNameForTypeSpec(inh.InheritedTypeSpec);
                use.AddIfNotPresent(netIface.Namespace);
                return(new CSIdentifier(netIface.TypeName));
            }));

            foreach (var funcDecl in proto.AllMethodsNoCDTor())
            {
                if (funcDecl.IsProperty && !funcDecl.IsSubscript)
                {
                    continue;
                }
                try {
                    CompileFunc(funcDecl, proto, iface, use);
                } catch (Exception e) {
                    errors.Add(ErrorHelper.CreateWarning(ReflectorError.kWrappingBase + 14, e, $"Error compiling ObjC protocol method {proto.ToFullyQualifiedName ()}.{funcDecl.Name}"));
                }
            }

            foreach (var propDecl in proto.AllProperties())
            {
                try {
                    CompileProp(propDecl, proto, iface, use);
                } catch (Exception e) {
                    errors.Add(ErrorHelper.CreateWarning(ReflectorError.kWrappingBase + 14, e, $"Error compiling ObjC protocol property {proto.ToFullyQualifiedName ()}.{propDecl.Name}"));
                }
            }
            var anyRequired = proto.AllMethodsNoCDTor().Any(func => !func.IsOptional);

            if (anyRequired)
            {
                kAbstractAttribute.AttachBefore(iface);
            }

            return(iface);
        }
        public static Tuple <CSNamespace, CSUsingPackages> CreateTestClass(CodeElementCollection <ICodeElement> callingCode, string testName,
                                                                           string expectedOutput, string nameSpace, string testClassName, CSClass otherClass, string skipReason, PlatformName platform)
        {
            var use = GetTestClassUsings(nameSpace);

            // [TomSkip(skipReason)]
            // public class TomTesttestName : ITomTest
            // {
            //    public testClassName() { }
            //    public string TestName { get { return testName; } }
            //    public string ExpectedOutput { get { return expectedOuput; } }
            //    public void Run() {
            //       callingCode;
            //    }
            // }
            // otherClass

            CSNamespace ns = new CSNamespace(nameSpace);

            if (otherClass != null)
            {
                ns.Block.Add(otherClass);
            }

            CSCodeBlock body = new CSCodeBlock(callingCode);

            body.Add(CaptureSwiftOutputPostlude(testName));

            CSMethod run = new CSMethod(CSVisibility.Public, CSMethodKind.None, CSSimpleType.Void, new CSIdentifier("Run"),
                                        new CSParameterList(), body);
            CSClass testClass = new CSClass(CSVisibility.Public, new CSIdentifier($"TomTest{testName}"), new CSMethod [] { run });

            testClass.Inheritance.Add(new CSIdentifier("ITomTest"));
            testClass.Properties.Add(MakeGetOnlyStringProp("TestName", testName));
            testClass.Properties.Add(MakeGetOnlyStringProp("ExpectedOutput", expectedOutput));
            ns.Block.Add(testClass);
            if (skipReason != null)
            {
                CSArgumentList al = new CSArgumentList();
                al.Add(CSConstant.Val(skipReason));
                CSAttribute attr = new CSAttribute("TomSkip", al);
                attr.AttachBefore(testClass);
            }
            return(new Tuple <CSNamespace, CSUsingPackages> (ns, use));
        }