/// <summary>
        /// Used for testing against Controller/Actions
        /// </summary>
        /// <param name="controllerType"></param>
        /// <param name="actionName"></param>
        /// <param name="parameterDescriptions"></param>
        /// <param name="supportedResponseTypes"></param>
        /// <returns></returns>
        protected OperationFilterContext FilterContextFor(Type controllerType, string actionName, List <ApiParameterDescription> parameterDescriptions = null, List <ApiResponseType> supportedResponseTypes = null)
        {
            var apiDescription = new ApiDescription
            {
                ActionDescriptor = new ControllerActionDescriptor
                {
                    ControllerTypeInfo = controllerType.GetTypeInfo(),
                    MethodInfo         = controllerType.GetMethod(actionName),
                }
            };

            var schemaRepository = new SchemaRepository();

            var methodInfo = controllerType.GetMethod(actionName);

            foreach (var parameterInfo in methodInfo.GetParameters())
            {
                schemaRepository.GetOrAdd(parameterInfo.ParameterType, parameterInfo.ParameterType.SchemaDefinitionName(), () => new OpenApiSchema()
                {
                    Reference = new OpenApiReference {
                        Id = parameterInfo.Name
                    }
                });
            }

            return(FilterContextFor(apiDescription, new CamelCasePropertyNamesContractResolver(), parameterDescriptions, supportedResponseTypes, schemaRepository));
        }
        protected OperationFilterContext FilterContextFor(Type controllerType, string actionName, IContractResolver contractResolver, List <ApiParameterDescription> parameterDescriptions = null, List <ApiResponseType> supportedResponseTypes = null)
        {
            var apiDescription = new ApiDescription
            {
                ActionDescriptor = new ControllerActionDescriptor
                {
                    ControllerTypeInfo = controllerType.GetTypeInfo(),
                    MethodInfo         = controllerType.GetMethod(actionName),
                }
            };

            if (parameterDescriptions != null)
            {
                apiDescription.With(api => api.ParameterDescriptions, parameterDescriptions);
            }

            if (supportedResponseTypes != null)
            {
                apiDescription.With(api => api.SupportedResponseTypes, supportedResponseTypes);
            }

            var jsonSerializerSettings = new JsonSerializerSettings
            {
                ContractResolver = contractResolver
            };

            var schemaOptions = new SchemaGeneratorOptions();

            var schemaRepository = new SchemaRepository();

            var methodInfo = controllerType.GetMethod(actionName);

            foreach (var parameterInfo in methodInfo.GetParameters())
            {
                schemaRepository.GetOrAdd(parameterInfo.ParameterType, parameterInfo.ParameterType.SchemaDefinitionName(), () => new OpenApiSchema()
                {
                    Reference = new OpenApiReference {
                        Id = parameterInfo.Name
                    }
                });
            }

            return(new OperationFilterContext(
                       apiDescription,
                       new NewtonsoftSchemaGenerator(schemaOptions, jsonSerializerSettings),
                       schemaRepository,
                       (apiDescription.ActionDescriptor as ControllerActionDescriptor).MethodInfo));
        }
        private OpenApiSchema CreateObjectSchema(Type type, SchemaRepository schemaRepository)
        {
            if (!(_contractResolver.ResolveContract(type) is JsonObjectContract jsonObjectContract))
            {
                throw new InvalidOperationException($"Type {type} does not resolve to a JsonObjectContract");
            }

            var schema = new OpenApiSchema
            {
                Type       = "object",
                Properties = new Dictionary <string, OpenApiSchema>(),
                Required   = new SortedSet <string>(),
                AdditionalPropertiesAllowed = false
            };

            // If it's a baseType with known subTypes, add the discriminator property
            if (_generatorOptions.GeneratePolymorphicSchemas && _generatorOptions.SubTypesResolver(type).Any())
            {
                var discriminatorName = _generatorOptions.DiscriminatorSelector(type);
                schema.Properties.Add(discriminatorName, new OpenApiSchema {
                    Type = "string"
                });
                schema.Required.Add(discriminatorName);
                schema.Discriminator = new OpenApiDiscriminator {
                    PropertyName = discriminatorName
                };
            }

            foreach (var jsonProperty in jsonObjectContract.Properties)
            {
                if (jsonProperty.Ignored)
                {
                    continue;
                }

                var customAttributes = jsonProperty.TryGetMemberInfo(out MemberInfo memberInfo)
                    ? memberInfo.GetInlineOrMetadataTypeAttributes()
                    : Enumerable.Empty <object>();

                if (_generatorOptions.IgnoreObsoleteProperties && customAttributes.OfType <ObsoleteAttribute>().Any())
                {
                    continue;
                }
                var required = jsonProperty.IsRequiredSpecified()
                    ? jsonProperty.Required
                    : jsonObjectContract.ItemRequired ?? Required.Default;

                schema.Properties[jsonProperty.PropertyName] = CreatePropertySchema(jsonProperty, customAttributes, required, schemaRepository);

                if (required == Required.Always || required == Required.AllowNull || customAttributes.OfType <RequiredAttribute>().Any())
                {
                    schema.Required.Add(jsonProperty.PropertyName);
                }
            }

            if (jsonObjectContract.ExtensionDataValueType != null)
            {
                schema.AdditionalProperties        = _schemaGenerator.GenerateSchema(jsonObjectContract.ExtensionDataValueType, schemaRepository);
                schema.AdditionalPropertiesAllowed = true;
            }

            // If it's a known subType, reference the baseType for inheritied properties
            if (_generatorOptions.GeneratePolymorphicSchemas && type.BaseType != null && _generatorOptions.SubTypesResolver(type.BaseType).Contains(type))
            {
                var baseType = type.BaseType;

                var baseSchemaReference = schemaRepository.GetOrAdd(
                    type: baseType,
                    schemaId: _generatorOptions.SchemaIdSelector(baseType),
                    factoryMethod: () => CreateObjectSchema(baseType, schemaRepository));

                var baseSchema = schemaRepository.Schemas[baseSchemaReference.Reference.Id];

                schema.AllOf = new[] { baseSchemaReference };

                foreach (var basePropertyName in baseSchema.Properties.Keys)
                {
                    schema.Properties.Remove(basePropertyName);
                }
            }

            return(schema);
        }