private void VerifyEnumGenBasic(AssemblyGenerator asmGen)
        {
            // Force this type to be shared to force failure
            asmGen.MockSharedCodeService.AddSharedType(typeof(System.IO.FileAttributes));

            string generatedCode = asmGen.GeneratedCode;

            Assert.IsFalse(string.IsNullOrEmpty(generatedCode), "Failed to generate code:\r\n" + asmGen.ConsoleLogger.Errors);

            Assembly assy = asmGen.GeneratedAssembly;

            Assert.IsNotNull(assy, "Assembly failed to build: " + asmGen.ConsoleLogger.Errors);

            TestHelper.AssertNoErrorsOrWarnings(asmGen.ConsoleLogger);

            // ------------------------------------------------------
            // Check the properties using enums were handled properly
            // ------------------------------------------------------
            Type clientEntityType = asmGen.GetGeneratedType(typeof(Enum_Basic_Entity).FullName);

            Assert.IsNotNull(clientEntityType, "Expected entity of type " + typeof(Enum_Basic_Entity));

            // Validate normal enum is generated
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "SizeProperty", typeof(SizeEnum), asmGen, /* expectNullable */ false);

            // Validate 2nd appearance of same enum is generated and does not gen 2nd decl of entity type (would fail compile)
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "SizeProperty2", typeof(SizeEnum), asmGen, /* expectNullable */ false);

            // Validate nullable form of same enum is generated and does not gen 2nd decl of entity type (would fail compile)
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "NullableSizeProperty", typeof(SizeEnum), asmGen, /* expectNullable */ true);

            // Validate nullable form of an enum *that is the only use of that enum type* generates the enum type
            // Regression test for 819356.
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "NullableOnlySizeProperty", typeof(SizeEnumNullableOnly), asmGen, /* expectNullable */ true);

            // Validate all integral forms of enum
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "SByteEnumProp", typeof(SByteEnum), asmGen, /* expectNullable */ false);
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "ByteEnumProp", typeof(ByteEnum), asmGen, /* expectNullable */ false);
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "ShortEnumProp", typeof(ShortEnum), asmGen, /* expectNullable */ false);
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "UShortEnumProp", typeof(UShortEnum), asmGen, /* expectNullable */ false);
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "IntEnumProp", typeof(IntEnum), asmGen, /* expectNullable */ false);
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "UIntEnumProp", typeof(UIntEnum), asmGen, /* expectNullable */ false);
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "LongEnumProp", typeof(LongEnum), asmGen, /* expectNullable */ false);
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "ULongEnumProp", typeof(ULongEnum), asmGen, /* expectNullable */ false);

            // Validate an enum with custom attributes on fields generates properly
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "CustomAttributeEnumProp", typeof(EnumWithCustomAttributes), asmGen, /* expectNullable */ false);

            // Validate an enum from another namespace propagates
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "SizePropertyOther", typeof(SizeEnumOther), asmGen, /* expectNullable */ false);

            // Validate a [Flags] enum propagates [Flags]
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "FlagProperty", typeof(FlagEnum), asmGen, /* expectNullable */ false);

            // DataContract enum was propagated
            this.ValidateGeneratedEnumProperty(typeof(Enum_Basic_Entity), "DCEnumProp", typeof(DataContractEnum), asmGen, /* expectNullable */ false);

            // Non-public property should not force enum to gen
            PropertyInfo propertyInfo = clientEntityType.GetProperty("SizePropertyNoGen");

            Assert.IsNull(propertyInfo, "The property SizePropertyNoGen should not have been generated because the property was not public.");

            Type clientEnumType = asmGen.GetGeneratedType(typeof(SizeEnumNoGen).FullName);

            Assert.IsNull(clientEnumType, "The SizeEnumNoGen type should not have been generated because only a private property exposed it.");

            // Non-public enum should not gen
            propertyInfo = clientEntityType.GetProperty("PrivateEnumProperty");
            Assert.IsNull(propertyInfo, "The property PrivateEnumProperty should not have been generated because the enum was not public.");

            clientEnumType = asmGen.GetGeneratedType(typeof(PrivateEnum).FullName);
            Assert.IsNull(clientEnumType, "The PrivateEnum type should not have been generated because it was not public.");

            // Shared System enum was used but not propagated
            propertyInfo = clientEntityType.GetProperty("FileAttrProp");
            Assert.IsNotNull(propertyInfo, "The property FileAttrProp should have been generated because the enum was shared.");
            Assert.AreEqual(typeof(FileAttributes).FullName, propertyInfo.PropertyType.FullName, "Expected FileAttrProp to use FileAttributes");


            // -----------------------------------------
            // Check DomainContext was generated with property custom method and invoke method
            // -----------------------------------------
            Type domainContextType = asmGen.GetGeneratedType("EnumGen.Tests.Enum_Basic_DomainContext");

            Assert.IsNotNull(domainContextType, "Expected to find domain context: EnumGen.Tests.Enum_Basic_DomainContext:\r\n" + asmGen.GeneratedTypeNames);

            // -------------------
            // Query method
            // -------------------

            // query method with enum arg should have generated that enum type
            clientEnumType = this.ValidateGeneratedEnum(typeof(QueryEnumArg), asmGen);

            // Query method should have been generated
            MethodInfo methodInfo = domainContextType.GetMethod("GetEntityWithEnumQuery");

            Assert.IsNotNull(methodInfo, "Expected to find query method called GetEntityWithEnumQuery");
            ParameterInfo[] parameters = methodInfo.GetParameters();
            Assert.AreEqual(1, parameters.Length, "Expected query method to have 1 parameter");
            this.ValidateGeneratedEnumReference(clientEnumType, parameters[0].ParameterType, /* expectNullable */ false);

            // Nullable form of query
            methodInfo = domainContextType.GetMethod("GetEntityWithNullableEnumQuery");
            Assert.IsNotNull(methodInfo, "Expected to find query method called GetEntityWithNullableEnumQuery");
            parameters = methodInfo.GetParameters();
            Assert.AreEqual(1, parameters.Length, "Expected query method to have 1 parameter");
            this.ValidateGeneratedEnumReference(clientEnumType, parameters[0].ParameterType, /* expectNullable */ true);

            // -------------------
            // Named update method
            // -------------------

            // Named update method with enum arg should have generated that enum type
            clientEnumType = this.ValidateGeneratedEnum(typeof(NamedEnumArg), asmGen);

            // Named update method should have been generated
            methodInfo = domainContextType.GetMethod("EnumNamedUpate");
            Assert.IsNotNull(methodInfo, "Expected to find named update method called EnumNamedUpdate");
            parameters = methodInfo.GetParameters();
            Assert.AreEqual(2, parameters.Length, "Expected named update method to have 2 parameters");
            this.ValidateGeneratedEnumReference(clientEnumType, parameters[1].ParameterType, /* expectNullable */ false);

            // Nullable form of named update method should have been generated
            methodInfo = domainContextType.GetMethod("EnumNamedUpateNullable");
            Assert.IsNotNull(methodInfo, "Expected to find named update method called EnumNamedUpdateNullable");
            parameters = methodInfo.GetParameters();
            Assert.AreEqual(2, parameters.Length, "Expected named update method to have 2 parameters");
            this.ValidateGeneratedEnumReference(clientEnumType, parameters[1].ParameterType, /* expectNullable */ true);

            // -------------------
            // Invoke method
            // -------------------

            // Should have generated the enum for the return and for its parameters
            Type invokeEnumRetType = this.ValidateGeneratedEnum(typeof(InvokeEnumRet), asmGen);
            Type invokeEnumArgType = this.ValidateGeneratedEnum(typeof(InvokeEnumArg), asmGen);

            // Should have generated our invoke signature
            methodInfo = domainContextType.GetMethod("EnumServiceOp", new Type[] { invokeEnumArgType });
            Assert.IsNotNull(methodInfo, "Expected service op for EnumServiceOp");
            Type returnType = methodInfo.ReturnType;

            Assert.IsTrue(returnType.IsGenericType, "Expected EnumServiceOp return type to be generic");
            Type genericType = returnType.GetGenericArguments()[0];

            Assert.AreEqual(invokeEnumRetType, genericType, "Expected EnumServiceOp<T> generic return type to be enum type");

            // Should have generated our nullable enum invoke signature
            methodInfo = domainContextType.GetMethod("EnumServiceOpNullable", new Type[] { invokeEnumArgType });
            Assert.IsNotNull(methodInfo, "Expected service op for EnumServiceOpNullable");
            returnType = methodInfo.ReturnType;
            Assert.IsTrue(returnType.IsGenericType, "Expected EnumServiceOp return type to be generic");
            genericType = returnType.GetGenericArguments()[0];
            this.ValidateGeneratedEnumReference(invokeEnumRetType, genericType, /* expectNullable */ true);
        }
        private void ValidateGeneratedEnumProperty(Type serverEntityType, string propertyName, Type serverEnumType, AssemblyGenerator asmGen, bool expectedNullable)
        {
            // Validate we generated the enum type
            Type clientEnumType = this.ValidateGeneratedEnum(serverEnumType, asmGen);

            Type clientEntityType = asmGen.GetGeneratedType(serverEntityType.FullName);

            Assert.IsNotNull(clientEntityType, "Expected client entity of type " + serverEntityType);

            PropertyInfo propertyInfo = clientEntityType.GetProperty(propertyName);

            Assert.IsNotNull(propertyInfo, "Expected property " + propertyName + " on entity type " + clientEntityType);

            this.ValidateGeneratedEnumReference(clientEnumType, propertyInfo.PropertyType, expectedNullable);
        }
        private Type ValidateGeneratedEnum(Type serverEnumType, AssemblyGenerator asmGen)
        {
            Type clientEnumType = asmGen.GetGeneratedType(serverEnumType.FullName);

            Assert.IsNotNull(clientEnumType, "Expected to see generated " + serverEnumType + " but saw " + asmGen.GeneratedTypeNames);

            // validate the enum integral type is the same
            Type serverUnderlyingType = serverEnumType.GetEnumUnderlyingType();
            Type clientUnderlyingType = clientEnumType.GetEnumUnderlyingType();

            Assert.AreEqual(serverUnderlyingType.FullName, clientUnderlyingType.FullName, "Mismatch in server enum type's underlying type and generated form");

            DataContractAttribute serverDCAttr = (DataContractAttribute)Attribute.GetCustomAttribute(serverEnumType, typeof(DataContractAttribute));

            if (serverDCAttr != null)
            {
                IList <CustomAttributeData> cads = AssemblyGenerator.GetCustomAttributeData(clientEnumType, typeof(DataContractAttribute));
                Assert.AreEqual(1, cads.Count, "Expected DataContract on " + clientEnumType);
                CustomAttributeData cad    = cads[0];
                string serverAttrName      = serverDCAttr.Name;
                string serverAttrNamespace = serverDCAttr.Namespace;
                string clientAttrName      = AssemblyGenerator.GetCustomAttributeValue <string>(cad, "Name");
                string clientAttrNamespace = AssemblyGenerator.GetCustomAttributeValue <string>(cad, "Namespace");

                Assert.AreEqual(serverAttrName, clientAttrName, "Expected DC.Name to be the same on " + clientEnumType);
                Assert.AreEqual(serverAttrNamespace, clientAttrNamespace, "Expected DC.Namespace to be the same on " + clientEnumType);
            }

            string[] serverMemberNames = Enum.GetNames(serverEnumType);
            string[] clientMemberNames = Enum.GetNames(clientEnumType);
            Assert.AreEqual(serverMemberNames.Length, clientMemberNames.Length, "Different number of fields generated");

            for (int i = 0; i < serverMemberNames.Length; ++i)
            {
                Assert.AreEqual(serverMemberNames[i], clientMemberNames[i], "Member name difference");

                // We have to use GetRawConstantValue because the ReflectionOnlyLoad does not support Enum.GetValues
                FieldInfo serverFieldInfo = serverEnumType.GetField(serverMemberNames[i]);
                Assert.IsNotNull(serverFieldInfo, "Failed to find server's " + serverMemberNames[i] + " as field info");
                object serverMemberValue = serverFieldInfo.GetRawConstantValue();

                FieldInfo clientFieldInfo = clientEnumType.GetField(clientMemberNames[i]);
                Assert.IsNotNull(clientFieldInfo, "Failed to find client's " + clientMemberNames[i] + " as field info");
                object clientMemberValue = clientFieldInfo.GetRawConstantValue();

                Assert.AreEqual(serverMemberValue, clientMemberValue, "Different values for field " + serverMemberNames[i]);

                EnumMemberAttribute enumMemberAttr = (EnumMemberAttribute)Attribute.GetCustomAttribute(serverFieldInfo, typeof(EnumMemberAttribute));
                if (enumMemberAttr != null)
                {
                    IList <CustomAttributeData> cads = AssemblyGenerator.GetCustomAttributeData(clientFieldInfo, typeof(EnumMemberAttribute));
                    Assert.AreEqual(1, cads.Count, "Expected EnumMember on " + clientEnumType + "." + clientMemberNames[i]);
                    CustomAttributeData cad = cads[0];
                    string clientValue      = null;
                    AssemblyGenerator.TryGetCustomAttributeValue <string>(cad, "Value", out clientValue);

                    string serverValue = enumMemberAttr.Value;
                    Assert.AreEqual(serverValue, clientValue, "EnumMember had different values for Value arg for " + clientEnumType + "." + clientMemberNames[i]);
                }

                // Validate Display custom attribute propagates correctly
                DisplayAttribute displayAttr = (DisplayAttribute)Attribute.GetCustomAttribute(serverFieldInfo, typeof(DisplayAttribute));
                if (displayAttr != null)
                {
                    IList <CustomAttributeData> cads = AssemblyGenerator.GetCustomAttributeData(clientFieldInfo, typeof(DisplayAttribute));
                    Assert.AreEqual(1, cads.Count, "Expected [Display] on " + clientEnumType + "." + clientMemberNames[i]);
                    CustomAttributeData cad = cads[0];
                    string clientValue      = null;
                    AssemblyGenerator.TryGetCustomAttributeValue <string>(cad, "Name", out clientValue);

                    string serverValue = displayAttr.Name;
                    Assert.AreEqual(serverValue, clientValue, "[Display] had different values for Name arg for " + clientEnumType + "." + clientMemberNames[i]);
                }

                // Validate Description custom attribute propagates correctly
                ComponentModelDescriptionAttribute descriptionAttr = (ComponentModelDescriptionAttribute)Attribute.GetCustomAttribute(serverFieldInfo, typeof(ComponentModelDescriptionAttribute));
                if (descriptionAttr != null)
                {
                    IList <CustomAttributeData> cads = AssemblyGenerator.GetCustomAttributeData(clientFieldInfo, typeof(ComponentModelDescriptionAttribute));
                    Assert.AreEqual(1, cads.Count, "Expected [Description] on " + clientEnumType + "." + clientMemberNames[i]);
                    CustomAttributeData cad = cads[0];
                    string clientValue      = null;
                    AssemblyGenerator.TryGetCustomAttributeValue <string>(cad, "Description", out clientValue);

                    string serverValue = descriptionAttr.Description;
                    Assert.AreEqual(serverValue, clientValue, "[Description] had different values for Description arg for " + clientEnumType + "." + clientMemberNames[i]);
                }

                // Validate ServerOnlyAttribute does not propagate
                ServerOnlyAttribute serverOnlyAttr = (ServerOnlyAttribute)Attribute.GetCustomAttribute(serverFieldInfo, typeof(ServerOnlyAttribute));
                if (serverOnlyAttr != null)
                {
                    IList <CustomAttributeData> cads = AssemblyGenerator.GetCustomAttributeData(clientFieldInfo, typeof(ServerOnlyAttribute));
                    Assert.AreEqual(0, cads.Count, "Expected [ServerOnlyAttribute] *not* to be generated on " + clientEnumType + "." + clientMemberNames[i]);
                }
            }

            bool serverHasFlags = serverEnumType.GetCustomAttributes(false).OfType <FlagsAttribute>().Any();

            // Have to use CustomAttributeData due to ReflectionOnly load
            IList <CustomAttributeData> clientFlagsAttributes = AssemblyGenerator.GetCustomAttributeData(clientEnumType, typeof(FlagsAttribute));
            bool clientHasFlags = clientFlagsAttributes.Any();

            Assert.AreEqual(serverHasFlags, clientHasFlags, "Server and client differ in appearance of [Flags]");

            return(clientEnumType);
        }
 private void VerifyTypeRefEntity(AssemblyGenerator asmGen, Type serverEntityType)
 {
     VerifyTypeRefEntityProperty(asmGen, serverEntityType, "NullableBindingFlags", typeof(Nullable <BindingFlags>));
     VerifyTypeRefEntityProperty(asmGen, serverEntityType, "ListOfBindingFlags", typeof(List <BindingFlags>));
 }