private static Type CreateTypeFromConfiguration(ConfigurationClassInfo configClass)
        {
            var typeBuilder = CreateTypeBuilder();

            if (!string.IsNullOrEmpty(configClass.ClassPrefix))
            {
                typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(
                                                   typeof(ConfigurationKeyPrefixAttribute).GetConstructor(new[] { typeof(string) }),
                                                   new object[] { configClass.ClassPrefix }));
            }

            foreach (var property in configClass.PropertyMap)
            {
                AddProperty(typeBuilder, property.Key, property.Value);
            }

            return(typeBuilder.CreateType());
        }
        public void CorrectlyHandlesTypes(ConfigurationClassInfo configClass)
        {
            // Arrange

            IConfigurationFactory configFactory =
                new ConfigurationFactory(
                    new DictionaryConfigurationProvider(
                        configClass.PropertyMap.ToDictionary(
                            property => (property.Value.ConfigKeyPrefix ?? configClass.ClassPrefix) + (property.Value.ConfigKey ?? property.Key),
                            property => property.Value.ExpectedValue)));

            var type = CreateTypeFromConfiguration(configClass);

            // Act
            var getConfig = new Func <object>(() => GetType()
                                              .GetMethod(nameof(GetConfig))
                                              .MakeGenericMethod(type)
                                              .Invoke(this, new object[] { configFactory }));

            var willSucceed = true;

            foreach (var configPair in configClass.PropertyMap)
            {
                var configPropertyInfo = configPair.Value;

                // True if the expected value is null or if it is an empty string.
                var expectedValueIsMissing =
                    configPropertyInfo.ExpectedValue == null ||
                    (configPropertyInfo.ExpectedValue is string && string.IsNullOrEmpty((string)configPropertyInfo.ExpectedValue));

                var isExpectedValueValid = IsValueValid(configPropertyInfo.ExpectedValue, configPropertyInfo.Type);
                var isDefaultValueValid  = IsValueValid(configPropertyInfo.DefaultValue, configPropertyInfo.Type);

                if ((configPropertyInfo.Required && expectedValueIsMissing) ||
                    !isExpectedValueValid ||
                    !isDefaultValueValid ||
                    configPropertyInfo.ConfigKey == string.Empty)
                {
                    // Acquiring the configuration will fail if a required attribute does not have an expected value.
                    // It will also fail if the expected value or default value cannot be converted into the type of the property.
                    // A null or empty configuration key will also fail.
                    willSucceed = false;
                    break;
                }
            }

            // Assert
            if (willSucceed)
            {
                var config = getConfig();
                foreach (var configPropertyPair in configClass.PropertyMap)
                {
                    var configPropertyInfo = configPropertyPair.Value;
                    Assert.Equal(configPropertyInfo.ExpectedValue ?? configPropertyInfo.DefaultValue,
                                 GetFromProperty(config, configPropertyPair.Key));
                }
            }
            else
            {
                // This will throw a TargetInvocationException instead of the exception thrown by ConfigurationFactory because we are using Reflection in getConfig.
                Assert.Throws <TargetInvocationException>(getConfig);
            }
        }