Log Warn Messages for ineffective Schema Validations, updated (#14759)

* Implement WARN messages for ineffective schema validation constraints

* Implement tests String, Number, Object schema validations

* Implement HashSet to store Validations for different types

* Revert Validation Helper functions; Add Test cases for Any and Boolean

* Implement Unit Test for Array with inffective schema validations

* Reformat Code; Optimize Imports

* Add assertions to ineffective validation tests

* Add Test case for Null Schema Validations

* Adjust log level and message

* Merge commit ... into issue-6491

---------

Co-authored-by: Chidu Nadig <chidu.nadig@gmail.com>
This commit is contained in:
martin-mfg 2023-03-14 04:16:18 +01:00 committed by GitHub
parent ecd28b2090
commit f5d31c5214
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 805 additions and 276 deletions

View File

@ -272,6 +272,12 @@
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-ext</artifactId>

View File

@ -25,11 +25,27 @@ import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Mustache.Compiler;
import com.samskivert.mustache.Mustache.Lambda;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.callbacks.Callback;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.*;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.servers.ServerVariable;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.text.StringEscapeUtils;
import org.openapitools.codegen.CodegenDiscriminator.MappedModel;
import org.openapitools.codegen.api.TemplatingEngineAdapter;
import org.openapitools.codegen.config.GlobalSettings;
@ -634,7 +650,7 @@ public class DefaultCodegen implements CodegenConfig {
parent.hasChildren = true;
Schema parentSchema = this.openAPI.getComponents().getSchemas().get(parent.name);
if (parentSchema == null) {
throw new NullPointerException(parent.name+" in "+this.openAPI.getComponents().getSchemas());
throw new NullPointerException(parent.name + " in " + this.openAPI.getComponents().getSchemas());
}
if (parentSchema.getDiscriminator() == null) {
parent = allModels.get(parent.getParent());
@ -2064,7 +2080,7 @@ public class DefaultCodegen implements CodegenConfig {
if (encoding != null) {
boolean styleGiven = true;
Encoding.StyleEnum style = encoding.getStyle();
if(style == null || style == Encoding.StyleEnum.FORM) {
if (style == null || style == Encoding.StyleEnum.FORM) {
// (Unfortunately, swagger-parser-v3 will always provide 'form'
// when style is not specified, so we can't detect that)
style = Encoding.StyleEnum.FORM;
@ -2072,12 +2088,12 @@ public class DefaultCodegen implements CodegenConfig {
}
boolean explodeGiven = true;
Boolean explode = encoding.getExplode();
if(explode == null) {
if (explode == null) {
explode = style == Encoding.StyleEnum.FORM; // Default to True when form, False otherwise
explodeGiven = false;
}
if(!styleGiven && !explodeGiven) {
if (!styleGiven && !explodeGiven) {
// Ignore contentType if style or explode are specified.
codegenParameter.contentType = encoding.getContentType();
}
@ -2085,7 +2101,7 @@ public class DefaultCodegen implements CodegenConfig {
codegenParameter.style = style.toString();
codegenParameter.isDeepObject = Encoding.StyleEnum.DEEP_OBJECT == style;
if(codegenParameter.isContainer) {
if (codegenParameter.isContainer) {
codegenParameter.isExplode = explode;
String collectionFormat = getCollectionFormat(codegenParameter);
codegenParameter.collectionFormat = StringUtils.isEmpty(collectionFormat) ? "csv" : collectionFormat;
@ -3032,7 +3048,6 @@ public class DefaultCodegen implements CodegenConfig {
// referenced models here, component that refs another component which is a model
// if a component references a schema which is not a generated model, the refed schema will be loaded into
// schema by unaliasSchema and one of the above code paths will be taken
;
}
if (schema.get$ref() != null) {
m.setRef(schema.get$ref());
@ -3942,7 +3957,7 @@ public class DefaultCodegen implements CodegenConfig {
}
property.baseType = getSchemaType(p);
if (p.getXml() != null) {
property.isXmlWrapped = p.getXml().getWrapped() == null ? false : p.getXml().getWrapped();
property.isXmlWrapped = p.getXml().getWrapped() != null && p.getXml().getWrapped();
property.xmlPrefix = p.getXml().getPrefix();
property.xmlNamespace = p.getXml().getNamespace();
property.xmlName = p.getXml().getName();
@ -5052,7 +5067,7 @@ public class DefaultCodegen implements CodegenConfig {
// the default value is false
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#user-content-parameterexplode
codegenParameter.isExplode = parameter.getExplode() == null ? false : parameter.getExplode();
codegenParameter.isExplode = parameter.getExplode() != null && parameter.getExplode();
// TODO revise collectionFormat, default collection format in OAS 3 appears to multi at least for query parameters
// https://swagger.io/docs/specification/serialization/
@ -5081,7 +5096,6 @@ public class DefaultCodegen implements CodegenConfig {
if (ModelUtils.isShortSchema(parameterSchema)) { // int32/short format
codegenParameter.isShort = true;
} else { // unbounded integer
;
}
}
} else if (ModelUtils.isTypeObjectSchema(parameterSchema)) {
@ -5093,7 +5107,6 @@ public class DefaultCodegen implements CodegenConfig {
}
addVarsRequiredVarsAdditionalProps(parameterSchema, codegenParameter);
} else if (ModelUtils.isNullType(parameterSchema)) {
;
} else if (ModelUtils.isAnyType(parameterSchema)) {
// any schema with no type set, composed schemas often do this
if (ModelUtils.isMapSchema(parameterSchema)) { // for map parameter
@ -5121,7 +5134,6 @@ public class DefaultCodegen implements CodegenConfig {
}
} else {
// referenced schemas
;
}
CodegenProperty codegenProperty = fromProperty(parameter.getName(), parameterSchema, false);
@ -6853,7 +6865,6 @@ public class DefaultCodegen implements CodegenConfig {
if (ModelUtils.isShortSchema(ps)) { // int32/short format
codegenParameter.isShort = true;
} else { // unbounded integer
;
}
}
} else if (ModelUtils.isTypeObjectSchema(ps)) {
@ -6861,10 +6872,8 @@ public class DefaultCodegen implements CodegenConfig {
codegenParameter.isFreeFormObject = true;
}
} else if (ModelUtils.isNullType(ps)) {
;
} else if (ModelUtils.isAnyType(ps)) {
// any schema with no type set, composed schemas often do this
;
} else if (ModelUtils.isArraySchema(ps)) {
Schema inner = getSchemaItems((ArraySchema) ps);
CodegenProperty arrayInnerProperty = fromProperty("inner", inner, false);
@ -6905,7 +6914,6 @@ public class DefaultCodegen implements CodegenConfig {
}
} else {
// referenced schemas
;
}
if (Boolean.TRUE.equals(codegenProperty.isModel)) {
@ -7809,9 +7817,9 @@ public class DefaultCodegen implements CodegenConfig {
return exceptions;
}
private String name;
private String removeCharRegEx;
private List<String> exceptions;
private final String name;
private final String removeCharRegEx;
private final List<String> exceptions;
@Override
public boolean equals(Object o) {
@ -7983,7 +7991,7 @@ public class DefaultCodegen implements CodegenConfig {
}
private CodegenComposedSchemas getComposedSchemas(Schema schema) {
if (!(schema instanceof ComposedSchema) && schema.getNot()==null) {
if (!(schema instanceof ComposedSchema) && schema.getNot() == null) {
return null;
}
Schema notSchema = schema.getNot();

View File

@ -28,11 +28,12 @@ import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.parser.ObjectMapperFactory;
import io.swagger.v3.parser.core.models.AuthorizationValue;
import io.swagger.v3.parser.util.ClasspathHelper;
import io.swagger.v3.parser.ObjectMapperFactory;
import io.swagger.v3.parser.util.RemoteUrl;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.IJsonSchemaValidationProperties;
@ -41,18 +42,17 @@ import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.io.FileUtils;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URLDecoder;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import static org.openapitools.codegen.utils.OnceLogger.once;
@ -71,29 +71,30 @@ public class ModelUtils {
private static final String freeFormExplicit = "x-is-free-form";
private static ObjectMapper JSON_MAPPER, YAML_MAPPER;
private static final ObjectMapper JSON_MAPPER;
private static final ObjectMapper YAML_MAPPER;
static {
JSON_MAPPER = ObjectMapperFactory.createJson();
YAML_MAPPER = ObjectMapperFactory.createYaml();
}
public static void setDisallowAdditionalPropertiesIfNotPresent(boolean value) {
GlobalSettings.setProperty(disallowAdditionalPropertiesIfNotPresent, Boolean.toString(value));
}
public static boolean isDisallowAdditionalPropertiesIfNotPresent() {
return Boolean.parseBoolean(GlobalSettings.getProperty(disallowAdditionalPropertiesIfNotPresent, "true"));
}
public static void setGenerateAliasAsModel(boolean value) {
GlobalSettings.setProperty(generateAliasAsModelKey, Boolean.toString(value));
public static void setDisallowAdditionalPropertiesIfNotPresent(boolean value) {
GlobalSettings.setProperty(disallowAdditionalPropertiesIfNotPresent, Boolean.toString(value));
}
public static boolean isGenerateAliasAsModel() {
return Boolean.parseBoolean(GlobalSettings.getProperty(generateAliasAsModelKey, "false"));
}
public static void setGenerateAliasAsModel(boolean value) {
GlobalSettings.setProperty(generateAliasAsModelKey, Boolean.toString(value));
}
public static boolean isGenerateAliasAsModel(Schema schema) {
return isGenerateAliasAsModel() || (schema.getExtensions() != null && schema.getExtensions().getOrDefault("x-generate-alias-as-model", false).equals(true));
}
@ -371,12 +372,6 @@ public class ModelUtils {
}
}
@FunctionalInterface
private static interface OpenAPISchemaVisitor {
public void visit(Schema schema, String mimeType);
}
public static String getSimpleRef(String ref) {
if (ref == null) {
once(LOGGER).warn("Failed to get the schema name: null");
@ -456,10 +451,7 @@ public class ModelUtils {
}
// must have at least one property
if (schema.getType() == null && schema.getProperties() != null && !schema.getProperties().isEmpty()) {
return true;
}
return false;
return schema.getType() == null && schema.getProperties() != null && !schema.getProperties().isEmpty();
}
/**
@ -560,11 +552,7 @@ public class ModelUtils {
return true;
}
if (schema.getAdditionalProperties() instanceof Boolean && (Boolean) schema.getAdditionalProperties()) {
return true;
}
return false;
return schema.getAdditionalProperties() instanceof Boolean && (Boolean) schema.getAdditionalProperties();
}
/**
@ -582,28 +570,20 @@ public class ModelUtils {
}
public static boolean isStringSchema(Schema schema) {
if (schema instanceof StringSchema || SchemaTypeUtil.STRING_TYPE.equals(schema.getType())) {
return true;
}
return false;
return schema instanceof StringSchema || SchemaTypeUtil.STRING_TYPE.equals(schema.getType());
}
public static boolean isIntegerSchema(Schema schema) {
if (schema instanceof IntegerSchema) {
return true;
}
if (SchemaTypeUtil.INTEGER_TYPE.equals(schema.getType())) {
return true;
}
return false;
return SchemaTypeUtil.INTEGER_TYPE.equals(schema.getType());
}
public static boolean isShortSchema(Schema schema) {
if (SchemaTypeUtil.INTEGER_TYPE.equals(schema.getType()) // type: integer
&& SchemaTypeUtil.INTEGER32_FORMAT.equals(schema.getFormat())) { // format: short (int32)
return true;
}
return false;
// format: short (int32)
return SchemaTypeUtil.INTEGER_TYPE.equals(schema.getType()) // type: integer
&& SchemaTypeUtil.INTEGER32_FORMAT.equals(schema.getFormat());
}
public static boolean isUnsignedIntegerSchema(Schema schema) {
@ -616,11 +596,9 @@ public class ModelUtils {
}
public static boolean isLongSchema(Schema schema) {
if (SchemaTypeUtil.INTEGER_TYPE.equals(schema.getType()) // type: integer
&& SchemaTypeUtil.INTEGER64_FORMAT.equals(schema.getFormat())) { // format: long (int64)
return true;
}
return false;
// format: long (int64)
return SchemaTypeUtil.INTEGER_TYPE.equals(schema.getType()) // type: integer
&& SchemaTypeUtil.INTEGER64_FORMAT.equals(schema.getFormat());
}
public static boolean isUnsignedLongSchema(Schema schema) {
@ -636,36 +614,26 @@ public class ModelUtils {
if (schema instanceof BooleanSchema) {
return true;
}
if (SchemaTypeUtil.BOOLEAN_TYPE.equals(schema.getType())) {
return true;
}
return false;
return SchemaTypeUtil.BOOLEAN_TYPE.equals(schema.getType());
}
public static boolean isNumberSchema(Schema schema) {
if (schema instanceof NumberSchema) {
return true;
}
if (SchemaTypeUtil.NUMBER_TYPE.equals(schema.getType())) {
return true;
}
return false;
return SchemaTypeUtil.NUMBER_TYPE.equals(schema.getType());
}
public static boolean isFloatSchema(Schema schema) {
if (SchemaTypeUtil.NUMBER_TYPE.equals(schema.getType())
&& SchemaTypeUtil.FLOAT_FORMAT.equals(schema.getFormat())) { // format: float
return true;
}
return false;
// format: float
return SchemaTypeUtil.NUMBER_TYPE.equals(schema.getType())
&& SchemaTypeUtil.FLOAT_FORMAT.equals(schema.getFormat());
}
public static boolean isDoubleSchema(Schema schema) {
if (SchemaTypeUtil.NUMBER_TYPE.equals(schema.getType())
&& SchemaTypeUtil.DOUBLE_FORMAT.equals(schema.getFormat())) { // format: double
return true;
}
return false;
// format: double
return SchemaTypeUtil.NUMBER_TYPE.equals(schema.getType())
&& SchemaTypeUtil.DOUBLE_FORMAT.equals(schema.getFormat());
}
public static boolean isDateSchema(Schema schema) {
@ -673,55 +641,45 @@ public class ModelUtils {
return true;
}
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.DATE_FORMAT.equals(schema.getFormat())) { // format: date
return true;
}
return false;
// format: date
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.DATE_FORMAT.equals(schema.getFormat());
}
public static boolean isDateTimeSchema(Schema schema) {
if (schema instanceof DateTimeSchema) {
return true;
}
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.DATE_TIME_FORMAT.equals(schema.getFormat())) { // format: date-time
return true;
}
return false;
// format: date-time
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.DATE_TIME_FORMAT.equals(schema.getFormat());
}
public static boolean isPasswordSchema(Schema schema) {
if (schema instanceof PasswordSchema) {
return true;
}
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.PASSWORD_FORMAT.equals(schema.getFormat())) { // double
return true;
}
return false;
// double
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.PASSWORD_FORMAT.equals(schema.getFormat());
}
public static boolean isByteArraySchema(Schema schema) {
if (schema instanceof ByteArraySchema) {
return true;
}
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.BYTE_FORMAT.equals(schema.getFormat())) { // format: byte
return true;
}
return false;
// format: byte
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.BYTE_FORMAT.equals(schema.getFormat());
}
public static boolean isBinarySchema(Schema schema) {
if (schema instanceof BinarySchema) {
return true;
}
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.BINARY_FORMAT.equals(schema.getFormat())) { // format: binary
return true;
}
return false;
// format: binary
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.BINARY_FORMAT.equals(schema.getFormat());
}
public static boolean isFileSchema(Schema schema) {
@ -736,38 +694,30 @@ public class ModelUtils {
if (schema instanceof UUIDSchema) {
return true;
}
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.UUID_FORMAT.equals(schema.getFormat())) { // format: uuid
return true;
}
return false;
// format: uuid
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.UUID_FORMAT.equals(schema.getFormat());
}
public static boolean isURISchema(Schema schema) {
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& URI_FORMAT.equals(schema.getFormat())) { // format: uri
return true;
}
return false;
// format: uri
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& URI_FORMAT.equals(schema.getFormat());
}
public static boolean isEmailSchema(Schema schema) {
if (schema instanceof EmailSchema) {
return true;
}
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.EMAIL_FORMAT.equals(schema.getFormat())) { // format: email
return true;
}
return false;
// format: email
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType())
&& SchemaTypeUtil.EMAIL_FORMAT.equals(schema.getFormat());
}
public static boolean isDecimalSchema(Schema schema) {
if (SchemaTypeUtil.STRING_TYPE.equals(schema.getType()) // type: string
&& "number".equals(schema.getFormat())) { // format: number
return true;
}
return false;
// format: number
return SchemaTypeUtil.STRING_TYPE.equals(schema.getType()) // type: string
&& "number".equals(schema.getFormat());
}
/**
@ -896,14 +846,10 @@ public class ModelUtils {
if (addlProps instanceof ObjectSchema) {
ObjectSchema objSchema = (ObjectSchema) addlProps;
// additionalProperties defined as {}
if (objSchema.getProperties() == null || objSchema.getProperties().isEmpty()) {
return true;
}
return objSchema.getProperties() == null || objSchema.getProperties().isEmpty();
} else if (addlProps instanceof Schema) {
// additionalProperties defined as {}
if (addlProps.getType() == null && addlProps.get$ref() == null && (addlProps.getProperties() == null || addlProps.getProperties().isEmpty())) {
return true;
}
return addlProps.getType() == null && addlProps.get$ref() == null && (addlProps.getProperties() == null || addlProps.getProperties().isEmpty());
}
}
}
@ -1412,7 +1358,6 @@ public class ModelUtils {
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue().stream().map(e -> e.getKey()).collect(Collectors.toList())));
}
/**
* Get the interfaces from the schema (composed)
*
@ -1683,18 +1628,15 @@ public class ModelUtils {
* either be null or a specified type:
* <p>
* OptionalOrder:
* oneOf:
* - type: 'null'
* - $ref: '#/components/schemas/Order'
* oneOf:
* - type: 'null'
* - $ref: '#/components/schemas/Order'
*
* @param schema the OpenAPI schema
* @return true if the schema is the 'null' type
*/
public static boolean isNullType(Schema schema) {
if ("null".equals(schema.getType())) {
return true;
}
return false;
return "null".equals(schema.getType());
}
/**
@ -1715,47 +1657,90 @@ public class ModelUtils {
public static void syncValidationProperties(Schema schema, IJsonSchemaValidationProperties target) {
// TODO move this method to IJsonSchemaValidationProperties
if (schema != null && target != null) {
if (isNullType(schema) || schema.get$ref() != null || isBooleanSchema(schema)) {
return;
}
Integer minItems = schema.getMinItems();
Integer maxItems = schema.getMaxItems();
Boolean uniqueItems = schema.getUniqueItems();
Integer minProperties = schema.getMinProperties();
Integer maxProperties = schema.getMaxProperties();
Integer minLength = schema.getMinLength();
Integer maxLength = schema.getMaxLength();
String pattern = schema.getPattern();
BigDecimal multipleOf = schema.getMultipleOf();
BigDecimal minimum = schema.getMinimum();
BigDecimal maximum = schema.getMaximum();
Boolean exclusiveMinimum = schema.getExclusiveMinimum();
Boolean exclusiveMaximum = schema.getExclusiveMaximum();
if (schema == null ||
target == null ||
schema.get$ref() != null)
return;
SchemaValidations.ValidationSetBuilder vSB = new SchemaValidations.ValidationSetBuilder();
if (isArraySchema(schema)) {
Integer minItems = schema.getMinItems();
if (minItems != null) vSB.withMinItems();
Integer maxItems = schema.getMaxItems();
if (maxItems != null) vSB.withMaxItems();
Boolean uniqueItems = schema.getUniqueItems();
if (uniqueItems != null) vSB.withUniqueItems();
Integer minProperties = schema.getMinProperties();
if (minProperties != null) vSB.withMinProperties();
Integer maxProperties = schema.getMaxProperties();
if (maxProperties != null) vSB.withMaxProperties();
Integer minLength = schema.getMinLength();
if (minLength != null) vSB.withMinLength();
Integer maxLength = schema.getMaxLength();
if (maxLength != null) vSB.withMaxLength();
String pattern = schema.getPattern();
if (pattern != null) vSB.withPattern();
BigDecimal multipleOf = schema.getMultipleOf();
if (multipleOf != null) vSB.withMultipleOf();
BigDecimal minimum = schema.getMinimum();
if (minimum != null) vSB.withMinimum();
BigDecimal maximum = schema.getMaximum();
if (maximum != null) vSB.withMaximum();
Boolean exclusiveMinimum = schema.getExclusiveMinimum();
if (exclusiveMinimum != null) vSB.withExclusiveMinimum();
Boolean exclusiveMaximum = schema.getExclusiveMaximum();
if (exclusiveMaximum != null) vSB.withExclusiveMaximum();
LinkedHashSet<String> setValidations = vSB.build();
if (isBooleanSchema(schema) || isNullType(schema)) {
logWarnMessagesForIneffectiveValidations(setValidations, schema, new HashSet<>());
} else if (isArraySchema(schema)) {
if (minItems != null || maxItems != null || uniqueItems != null)
setArrayValidations(minItems, maxItems, uniqueItems, target);
} else if (isTypeObjectSchema(schema)) {
logWarnMessagesForIneffectiveValidations(new LinkedHashSet(setValidations), schema, SchemaValidations.ARRAY_VALIDATIONS);
} else if (isTypeObjectSchema(schema)) {
if (minProperties != null || maxProperties != null)
setObjectValidations(minProperties, maxProperties, target);
} else if (isStringSchema(schema)) {
logWarnMessagesForIneffectiveValidations(new LinkedHashSet(setValidations), schema, SchemaValidations.OBJECT_VALIDATIONS);
} else if (isStringSchema(schema)) {
if (minLength != null || maxLength != null || pattern != null)
setStringValidations(minLength, maxLength, pattern, target);
if (isDecimalSchema(schema)) {
if (isDecimalSchema(schema)) {
if (multipleOf != null || minimum != null || maximum != null || exclusiveMinimum != null || exclusiveMaximum != null)
setNumericValidations(schema, multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum, target);
}
} else if (isNumberSchema(schema) || isIntegerSchema(schema)) {
setNumericValidations(schema, multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum, target);
} else if (isAnyType(schema)) {
// anyType can have any validations set on it
setArrayValidations(minItems, maxItems, uniqueItems, target);
setObjectValidations(minProperties, maxProperties, target);
setStringValidations(minLength, maxLength, pattern, target);
setNumericValidations(schema, multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum, target);
}
if (maxItems != null || minItems != null || minProperties != null || maxProperties != null || minLength != null || maxLength != null || multipleOf != null || pattern != null || minimum != null || maximum != null || exclusiveMinimum != null || exclusiveMaximum != null || uniqueItems != null) {
target.setHasValidation(true);
}
Set<String> stringAndNumericValidations = new HashSet<>(SchemaValidations.STRING_VALIDATIONS);
stringAndNumericValidations.addAll(SchemaValidations.NUMERIC_VALIDATIONS);
logWarnMessagesForIneffectiveValidations(new LinkedHashSet(setValidations), schema, stringAndNumericValidations);
} else
logWarnMessagesForIneffectiveValidations(new LinkedHashSet(setValidations), schema, SchemaValidations.STRING_VALIDATIONS);
} else if (isNumberSchema(schema) || isIntegerSchema(schema)) {
if (multipleOf != null || minimum != null || maximum != null || exclusiveMinimum != null || exclusiveMaximum != null)
setNumericValidations(schema, multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum, target);
logWarnMessagesForIneffectiveValidations(new LinkedHashSet(setValidations), schema, SchemaValidations.NUMERIC_VALIDATIONS);
} else if (isAnyType(schema)) {
// anyType can have any validations set on it
setArrayValidations(minItems, maxItems, uniqueItems, target);
setObjectValidations(minProperties, maxProperties, target);
setStringValidations(minLength, maxLength, pattern, target);
setNumericValidations(schema, multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum, target);
}
if (!setValidations.isEmpty())
target.setHasValidation(true);
}
private static void setArrayValidations(Integer minItems, Integer maxItems, Boolean uniqueItems, IJsonSchemaValidationProperties target) {
@ -1796,6 +1781,13 @@ public class ModelUtils {
}
}
private static void logWarnMessagesForIneffectiveValidations(Set<String> setValidations, Schema schema, Set<String> effectiveValidations) {
setValidations.removeAll(effectiveValidations);
setValidations.stream().forEach(validation -> {
LOGGER.warn("Validation '" + validation + "' has no effect on schema '"+ schema.getType() +"'. Ignoring!");
});
}
private static ObjectMapper getRightMapper(String data) {
ObjectMapper mapper;
if (data.trim().startsWith("{")) {
@ -1986,4 +1978,125 @@ public class ModelUtils {
return false;
}
@FunctionalInterface
private interface OpenAPISchemaVisitor {
void visit(Schema schema, String mimeType);
}
private static final class SchemaValidations {
public static Set<String> ARRAY_VALIDATIONS = new ValidationSetBuilder()
.withMinItems()
.withMaxItems()
.withUniqueItems()
.build();
public static Set<String> OBJECT_VALIDATIONS = new ValidationSetBuilder()
.withMinProperties()
.withMaxProperties()
.build();
public static Set<String> STRING_VALIDATIONS = new ValidationSetBuilder()
.withMinLength()
.withMaxLength()
.withPattern()
.build();
public static Set<String> NUMERIC_VALIDATIONS = new ValidationSetBuilder()
.withMultipleOf()
.withMinimum()
.withMaximum()
.withExclusiveMinimum()
.withExclusiveMaximum()
.build();
public static Set<String> ALL_VALIDATIONS;
static {
ALL_VALIDATIONS = new HashSet<>(ARRAY_VALIDATIONS);
ALL_VALIDATIONS.addAll(OBJECT_VALIDATIONS);
ALL_VALIDATIONS.addAll(STRING_VALIDATIONS);
ALL_VALIDATIONS.addAll(NUMERIC_VALIDATIONS);
}
SchemaValidations() {
}
public static class ValidationSetBuilder {
LinkedHashSet<String> validationSet;
ValidationSetBuilder() {
this.validationSet = new LinkedHashSet<String>();
}
public ValidationSetBuilder withMinItems() {
this.validationSet.add("minItems");
return this;
}
public ValidationSetBuilder withMaxItems() {
this.validationSet.add("maxItems");
return this;
}
public ValidationSetBuilder withUniqueItems() {
this.validationSet.add("uniqueItems");
return this;
}
public ValidationSetBuilder withMinProperties() {
this.validationSet.add("minProperties");
return this;
}
public ValidationSetBuilder withMaxProperties() {
this.validationSet.add("maxProperties");
return this;
}
public ValidationSetBuilder withMinLength() {
this.validationSet.add("minLength");
return this;
}
public ValidationSetBuilder withMaxLength() {
this.validationSet.add("maxLength");
return this;
}
public ValidationSetBuilder withPattern() {
this.validationSet.add("pattern");
return this;
}
public ValidationSetBuilder withMultipleOf() {
this.validationSet.add("multipleOf");
return this;
}
public ValidationSetBuilder withMinimum() {
this.validationSet.add("minimum");
return this;
}
public ValidationSetBuilder withMaximum() {
this.validationSet.add("maximum");
return this;
}
public ValidationSetBuilder withExclusiveMinimum() {
this.validationSet.add("exclusiveMinimum");
return this;
}
public ValidationSetBuilder withExclusiveMaximum() {
this.validationSet.add("exclusiveMaximum");
return this;
}
public LinkedHashSet<String> build() {
return this.validationSet;
}
}
}
}

View File

@ -17,9 +17,13 @@
package org.openapitools.codegen;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import com.google.common.collect.Sets;
import com.samskivert.mustache.Mustache.Lambda;
import io.swagger.parser.OpenAPIParser;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
@ -33,18 +37,14 @@ import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.parser.core.models.ParseOptions;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.config.GlobalSettings;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.templating.mustache.CamelCaseLambda;
import org.openapitools.codegen.templating.mustache.IndentedLambda;
import org.openapitools.codegen.templating.mustache.LowercaseLambda;
import org.openapitools.codegen.templating.mustache.TitlecaseLambda;
import org.openapitools.codegen.templating.mustache.UppercaseLambda;
import org.openapitools.codegen.templating.mustache.*;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.SemVer;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
@ -54,10 +54,13 @@ import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;
import static junit.framework.Assert.assertEquals;
import static org.testng.Assert.*;
public class DefaultCodegenTest {
private static final Logger testLogger = (Logger) LoggerFactory.getLogger(ModelUtils.class);
@Test
public void testDeeplyNestedAdditionalPropertiesImports() {
final DefaultCodegen codegen = new DefaultCodegen();
@ -667,7 +670,6 @@ public class DefaultCodegenTest {
Assert.assertTrue(colorSeen);
}
@Test
public void testEscapeText() {
final DefaultCodegen codegen = new DefaultCodegen();
@ -1591,7 +1593,6 @@ public class DefaultCodegenTest {
assertEquals(cm.discriminator, discriminator);
}
@Test
public void testAllOfSingleRefNoOwnProps() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/2_0/composed-allof.yaml");
@ -1605,14 +1606,6 @@ public class DefaultCodegenTest {
Assert.assertNull(model.allParents);
}
class CodegenWithMultipleInheritance extends DefaultCodegen {
public CodegenWithMultipleInheritance() {
super();
supportsInheritance = true;
supportsMultipleInheritance = true;
}
}
@Test
public void testAllOfParent() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/allOf-required-parent.yaml");
@ -2238,83 +2231,6 @@ public class DefaultCodegenTest {
assertEquals(codegen.toApiName(""), "DefaultApi");
}
public static class FromParameter {
private CodegenParameter codegenParameter(String path) {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/fromParameter.yaml");
new InlineModelResolver().flatten(openAPI);
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
return codegen
.fromParameter(
openAPI
.getPaths()
.get(path)
.getGet()
.getParameters()
.get(0),
new HashSet<>()
);
}
@Test
public void setStyle() {
CodegenParameter parameter = codegenParameter("/set_style");
assertEquals(parameter.style, "form");
}
@Test
public void setShouldExplode() {
CodegenParameter parameter = codegenParameter("/set_should_explode");
assertTrue(parameter.isExplode);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_Boolean_true() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, true);
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertTrue(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_Boolean_false() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, false);
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertFalse(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_String_true() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, "true");
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertTrue(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_String_false() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, "false");
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertFalse(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_String_blibb() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, "blibb");
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertFalse(result);
}
}
@Test
public void testCircularReferencesDetection() {
// given
@ -2464,7 +2380,7 @@ public class DefaultCodegenTest {
"post",
path.getPost(),
path.getServers());
assertEquals(operation.formParams.size(), 3,
Assert.assertEquals(operation.formParams.size(), 3,
"The list of parameters should include inherited type");
final List<String> names = operation.formParams.stream()
@ -3750,7 +3666,7 @@ public class DefaultCodegenTest {
modelName = "ObjectWithComposedProperties";
CodegenModel m = codegen.fromModel(modelName, openAPI.getComponents().getSchemas().get(modelName));
/* TODO inline allOf schema are created as separate models and the following assumptions that
the properties are non-model are no longer valid and need to be revised
the properties are non-model are no longer valid and need to be revised
assertTrue(m.vars.get(0).getIsMap());
assertTrue(m.vars.get(1).getIsNumber());
assertTrue(m.vars.get(2).getIsUnboundedInteger());
@ -4242,6 +4158,356 @@ public class DefaultCodegenTest {
Assert.assertEquals(codegenParameter.getSchema(), null);
}
@Test
public void testArraySchemaWithIneffectiveConstraints() {
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
testLogger.addAppender(listAppender);
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue6491.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "ArrayWithIneffectiveValidations";
Schema sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel cm = codegen.fromModel(modelName, sc);
List<ILoggingEvent> logsList = listAppender.list;
// JUnit assertions
assertEquals(16, logsList.size());
assertEquals("Validation 'minProperties' has no effect on schema 'array'. Ignoring!", logsList.get(0)
.getMessage());
assertEquals("Validation 'maxProperties' has no effect on schema 'array'. Ignoring!", logsList.get(1)
.getMessage());
assertEquals("Validation 'minLength' has no effect on schema 'array'. Ignoring!", logsList.get(2)
.getMessage());
assertEquals("Validation 'maxLength' has no effect on schema 'array'. Ignoring!", logsList.get(3)
.getMessage());
assertEquals("Validation 'pattern' has no effect on schema 'array'. Ignoring!", logsList.get(4)
.getMessage());
assertEquals("Validation 'multipleOf' has no effect on schema 'array'. Ignoring!", logsList.get(5)
.getMessage());
assertEquals("Validation 'minimum' has no effect on schema 'array'. Ignoring!", logsList.get(6)
.getMessage());
assertEquals("Validation 'maximum' has no effect on schema 'array'. Ignoring!", logsList.get(7)
.getMessage());
// Assert all logged messages are WARN messages
logsList.stream().limit(8).forEach(log -> assertEquals(Level.WARN, log.getLevel()));
}
@Test
public void testObjectSchemaWithIneffectiveConstraints() {
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
testLogger.addAppender(listAppender);
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue6491.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "ObjectWithIneffectiveValidations";
Schema sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel cm = codegen.fromModel(modelName, sc);
List<ILoggingEvent> logsList = listAppender.list;
// JUnit assertions
assertEquals(9, logsList.size());
assertEquals("Validation 'minItems' has no effect on schema 'object'. Ignoring!", logsList.get(0)
.getMessage());
assertEquals("Validation 'maxItems' has no effect on schema 'object'. Ignoring!", logsList.get(1)
.getMessage());
assertEquals("Validation 'uniqueItems' has no effect on schema 'object'. Ignoring!", logsList.get(2)
.getMessage());
assertEquals("Validation 'minLength' has no effect on schema 'object'. Ignoring!", logsList.get(3)
.getMessage());
assertEquals("Validation 'maxLength' has no effect on schema 'object'. Ignoring!", logsList.get(4)
.getMessage());
assertEquals("Validation 'pattern' has no effect on schema 'object'. Ignoring!", logsList.get(5)
.getMessage());
assertEquals("Validation 'multipleOf' has no effect on schema 'object'. Ignoring!", logsList.get(6)
.getMessage());
assertEquals("Validation 'minimum' has no effect on schema 'object'. Ignoring!", logsList.get(7)
.getMessage());
assertEquals("Validation 'maximum' has no effect on schema 'object'. Ignoring!", logsList.get(8)
.getMessage());
// Assert all logged messages are WARN messages
logsList.stream().forEach(log -> assertEquals(Level.WARN, log.getLevel()));
}
@Test
public void testStringSchemaWithIneffectiveConstraints() {
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
testLogger.addAppender(listAppender);
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue6491.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "StringWithIneffectiveValidations";
Schema sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel cm = codegen.fromModel(modelName, sc);
List<ILoggingEvent> logsList = listAppender.list;
// JUnit assertions
assertEquals(8, logsList.size());
assertEquals("Validation 'minItems' has no effect on schema 'string'. Ignoring!", logsList.get(0)
.getMessage());
assertEquals("Validation 'maxItems' has no effect on schema 'string'. Ignoring!", logsList.get(1)
.getMessage());
assertEquals("Validation 'uniqueItems' has no effect on schema 'string'. Ignoring!", logsList.get(2)
.getMessage());
assertEquals("Validation 'minProperties' has no effect on schema 'string'. Ignoring!", logsList.get(3)
.getMessage());
assertEquals("Validation 'maxProperties' has no effect on schema 'string'. Ignoring!", logsList.get(4)
.getMessage());
assertEquals("Validation 'multipleOf' has no effect on schema 'string'. Ignoring!", logsList.get(5)
.getMessage());
assertEquals("Validation 'minimum' has no effect on schema 'string'. Ignoring!", logsList.get(6)
.getMessage());
assertEquals("Validation 'maximum' has no effect on schema 'string'. Ignoring!", logsList.get(7)
.getMessage());
// Assert all logged messages are WARN messages
logsList.stream().forEach(log -> assertEquals(Level.WARN, log.getLevel()));
}
@Test
public void testIntegerSchemaWithIneffectiveConstraints() {
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
testLogger.addAppender(listAppender);
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue6491.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "IntegerWithIneffectiveValidations";
Schema sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel cm = codegen.fromModel(modelName, sc);
List<ILoggingEvent> logsList = listAppender.list;
// JUnit assertions
assertEquals(8, logsList.size());
assertEquals("Validation 'minItems' has no effect on schema 'integer'. Ignoring!", logsList.get(0)
.getMessage());
assertEquals("Validation 'maxItems' has no effect on schema 'integer'. Ignoring!", logsList.get(1)
.getMessage());
assertEquals("Validation 'uniqueItems' has no effect on schema 'integer'. Ignoring!", logsList.get(2)
.getMessage());
assertEquals("Validation 'minProperties' has no effect on schema 'integer'. Ignoring!", logsList.get(3)
.getMessage());
assertEquals("Validation 'maxProperties' has no effect on schema 'integer'. Ignoring!", logsList.get(4)
.getMessage());
assertEquals("Validation 'minLength' has no effect on schema 'integer'. Ignoring!", logsList.get(5)
.getMessage());
assertEquals("Validation 'maxLength' has no effect on schema 'integer'. Ignoring!", logsList.get(6)
.getMessage());
assertEquals("Validation 'pattern' has no effect on schema 'integer'. Ignoring!", logsList.get(7)
.getMessage());
// Assert all logged messages are WARN messages
logsList.stream().forEach(log -> assertEquals(Level.WARN, log.getLevel()));
}
@Test
public void testAnySchemaWithIneffectiveConstraints() {
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
testLogger.addAppender(listAppender);
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue6491.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "AnyTypeWithIneffectiveValidations";
Schema sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel cm = codegen.fromModel(modelName, sc);
List<ILoggingEvent> logsList = listAppender.list;
// JUnit assertions
assertEquals(0, logsList.size());
}
@Test
public void testBooleanSchemaWithIneffectiveConstraints() {
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
testLogger.addAppender(listAppender);
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue6491.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "BooleanWithIneffectiveValidations";
Schema sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel cm = codegen.fromModel(modelName, sc);
List<ILoggingEvent> logsList = listAppender.list;
// JUnit assertions
assertEquals(11, logsList.size());
assertEquals("Validation 'minItems' has no effect on schema 'boolean'. Ignoring!", logsList.get(0)
.getMessage());
assertEquals("Validation 'maxItems' has no effect on schema 'boolean'. Ignoring!", logsList.get(1)
.getMessage());
assertEquals("Validation 'uniqueItems' has no effect on schema 'boolean'. Ignoring!", logsList.get(2)
.getMessage());
assertEquals("Validation 'minProperties' has no effect on schema 'boolean'. Ignoring!", logsList.get(3)
.getMessage());
assertEquals("Validation 'maxProperties' has no effect on schema 'boolean'. Ignoring!", logsList.get(4)
.getMessage());
assertEquals("Validation 'minLength' has no effect on schema 'boolean'. Ignoring!", logsList.get(5)
.getMessage());
assertEquals("Validation 'maxLength' has no effect on schema 'boolean'. Ignoring!", logsList.get(6)
.getMessage());
assertEquals("Validation 'pattern' has no effect on schema 'boolean'. Ignoring!", logsList.get(7)
.getMessage());
assertEquals("Validation 'multipleOf' has no effect on schema 'boolean'. Ignoring!", logsList.get(8)
.getMessage());
assertEquals("Validation 'minimum' has no effect on schema 'boolean'. Ignoring!", logsList.get(9)
.getMessage());
assertEquals("Validation 'maximum' has no effect on schema 'boolean'. Ignoring!", logsList.get(10)
.getMessage());
// Assert all logged messages are WARN messages
logsList.stream().forEach(log -> assertEquals(Level.WARN, log.getLevel()));
}
@Test
public void testNullSchemaWithIneffectiveConstraints() {
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
listAppender.start();
// add the appender to the logger
testLogger.addAppender(listAppender);
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue6491.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "NullWithIneffectiveValidations";
Schema sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel cm = codegen.fromModel(modelName, sc);
List<ILoggingEvent> logsList = listAppender.list;
// JUnit assertions
assertEquals(0, logsList.size());
}
public static class FromParameter {
private CodegenParameter codegenParameter(String path) {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/fromParameter.yaml");
new InlineModelResolver().flatten(openAPI);
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
return codegen
.fromParameter(
openAPI
.getPaths()
.get(path)
.getGet()
.getParameters()
.get(0),
new HashSet<>()
);
}
@Test
public void setStyle() {
CodegenParameter parameter = codegenParameter("/set_style");
assertEquals(parameter.style, "form");
}
@Test
public void setShouldExplode() {
CodegenParameter parameter = codegenParameter("/set_should_explode");
assertTrue(parameter.isExplode);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_Boolean_true() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, true);
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertTrue(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_Boolean_false() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, false);
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertFalse(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_String_true() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, "true");
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertTrue(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_String_false() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, "false");
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertFalse(result);
}
@Test
public void testConvertPropertyToBooleanAndWriteBack_String_blibb() {
final DefaultCodegen codegen = new DefaultCodegen();
Map<String, Object> additionalProperties = codegen.additionalProperties();
additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, "blibb");
boolean result = codegen.convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL);
Assert.assertFalse(result);
}
}
class CodegenWithMultipleInheritance extends DefaultCodegen {
public CodegenWithMultipleInheritance() {
super();
supportsInheritance = true;
supportsMultipleInheritance = true;
}
}
@Test
public void testFromPropertyRequiredAndOptional() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_12857.yaml");

View File

@ -0,0 +1,124 @@
openapi: 3.0.1
info:
title: My title
description: API under test
version: 1.0.7
servers:
- url: https://localhost:9999/root
paths:
/location:
get:
operationId: getLocation
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/ArrayWithIneffectiveValidations'
components:
schemas:
ArrayWithIneffectiveValidations:
type: array
items: {}
minProperties: 1
maxProperties: 5
minLength: 1
maxLength: 5
pattern: 'abcde'
multipleOf: 3
minimum: 1
maximum: 10
exclusiveMinimum: 0
exclusiveMaximum: 100
ObjectWithIneffectiveValidations:
type: object
properties:
id:
type: integer
name:
type: string
minItems: 1
maxItems: 5
uniqueItems: true
minLength: 1
maxLength: 10
pattern: 'abcde'
multipleOf: 3
minimum: 1
maximum: 10
exclusiveMinimum: 1
exclusiveMaximum: 10
StringWithIneffectiveValidations:
type: string
minItems: 1
maxItems: 5
uniqueItems: true
minProperties: 1
maxProperties: 5
multipleOf: 3
minimum: 1
maximum: 10
exclusiveMinimum: 0
exclusiveMaximum: 100
IntegerWithIneffectiveValidations:
type: integer
minItems: 1
maxItems: 5
uniqueItems: true
minProperties: 1
maxProperties: 5
minLength: 1
maxLength: 10
pattern: 'abcde'
AnyTypeWithIneffectiveValidations:
minItems: 1
maxItems: 5
uniqueItems: true
minProperties: 1
maxProperties: 5
minLength: 1
maxLength: 10
pattern: 'abcde'
multipleOf: 4
minimum: 1
maximum: 99
exclusiveMinimum: 0
exclusiveMaximum: 100
BooleanWithIneffectiveValidations:
type: boolean
minItems: 1
maxItems: 5
uniqueItems: true
minProperties: 1
maxProperties: 5
minLength: 1
maxLength: 10
pattern: 'abcde'
multipleOf: 4
minimum: 1
maximum: 99
exclusiveMinimum: 0
exclusiveMaximum: 100
NullWithIneffectiveValidations:
type: null
minItems: 1
maxItems: 5
uniqueItems: true
minProperties: 1
maxProperties: 5
minLength: 1
maxLength: 10
pattern: 'abcde'
multipleOf: 4
minimum: 1
maximum: 99
exclusiveMinimum: 0
exclusiveMaximum: 100

View File

@ -0,0 +1,11 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -1,10 +1,11 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>5</version>
<relativePath/><!-- lookup parent from repository -->
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.openapitools</groupId>