ModelResolverOAS31Test.java
package io.swagger.v3.core.resolving.v31;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverterContextImpl;
import io.swagger.v3.core.converter.ModelConverters;
import io.swagger.v3.core.jackson.ModelResolver;
import io.swagger.v3.core.matchers.SerializationMatchers;
import io.swagger.v3.core.resolving.SwaggerTestBase;
import io.swagger.v3.core.resolving.resources.TestArrayType;
import io.swagger.v3.core.resolving.resources.TestObject4715;
import io.swagger.v3.core.resolving.v31.model.AnnotatedArray;
import io.swagger.v3.core.resolving.v31.model.AnnotatedArrayProperty;
import io.swagger.v3.core.resolving.v31.model.AnnotatedArrayPropertyWriteOnly;
import io.swagger.v3.core.resolving.v31.model.AnnotatedArrayPropertyReadWrite;
import io.swagger.v3.core.resolving.v31.model.ModelWithDependentSchema;
import io.swagger.v3.core.resolving.v31.model.ModelWithOAS31Stuff;
import io.swagger.v3.oas.models.media.Schema;
import org.testng.annotations.Test;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.util.List;
import java.util.Map;
public class ModelResolverOAS31Test extends SwaggerTestBase {
@Test
public void testAnnotatedArray() {
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema model = context.resolve(new AnnotatedType(AnnotatedArray.class));
SerializationMatchers.assertEqualsToYaml31(model, "type: array\n" +
"contains:\n" +
" type: string\n" +
"description: arraydescription\n" +
"items:\n" +
" type: string\n" +
" description: itemdescription\n"+
"maxContains: 10\n" +
"minContains: 1\n" +
"prefixItems:\n" +
"- type: string\n" +
"unevaluatedItems:\n" +
" type: number\n");
}
@Test
public void testAnnotatedArrayProperty() {
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema model = context.resolve(new AnnotatedType(AnnotatedArrayProperty.class));
SerializationMatchers.assertEqualsToYaml31(model,
"type: object\n" +
"properties:\n" +
" randomList:\n" +
" type: array\n" +
" contains:\n" +
" type: string\n" +
" deprecated: true\n" +
" description: arraydescription\n" +
" examples:\n" +
" - John\n" +
" items:\n" +
" type: string\n" +
" description: itemdescription\n" +
" title: itemtitle\n" +
" maxContains: 10\n" +
" minContains: 1\n" +
" prefixItems:\n" +
" - type: string\n" +
" description: prefixdescription\n" +
" readOnly: true\n" +
" title: arraytitle\n" +
" unevaluatedItems:\n" +
" type: number");
}
@Test
public void testAnnotatedArrayPropertyWriteOnly() {
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema model = context.resolve(new AnnotatedType(AnnotatedArrayPropertyWriteOnly.class));
SerializationMatchers.assertEqualsToYaml31(model,
"type: object\n" +
"properties:\n" +
" randomList:\n" +
" type: array\n" +
" description: arraydescription\n" +
" examples:\n" +
" - Jane\n" +
" items:\n" +
" type: string\n" +
" description: itemdescription\n" +
" title: itemtitle\n" +
" maxContains: 5\n" +
" minContains: 1\n" +
" title: arraytitle\n" +
" writeOnly: true");
}
@Test
public void testAnnotatedArrayPropertyReadWrite() {
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema model = context.resolve(new AnnotatedType(AnnotatedArrayPropertyReadWrite.class));
SerializationMatchers.assertEqualsToYaml31(model,
"type: object\n" +
"properties:\n" +
" randomList:\n" +
" type: array\n" +
" description: arraydescription\n" +
" examples:\n" +
" - Bob\n" +
" items:\n" +
" type: string\n" +
" description: itemdescription\n" +
" title: itemtitle\n" +
" maxContains: 8\n" +
" minContains: 2\n" +
" title: arraytitle");
}
@Test
public void testOAS31Fields() {
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
Schema model = context.resolve(new AnnotatedType(ModelWithOAS31Stuff.class));
SerializationMatchers.assertEqualsToYaml31(context.getDefinedModels(), "Address:\n" +
" type: object\n" +
" if:\n" +
" $ref: \"#/components/schemas/AnnotatedCountry\"\n" +
" then:\n" +
" $ref: \"#/components/schemas/PostalCodeNumberPattern\"\n" +
" else:\n" +
" $ref: \"#/components/schemas/PostalCodePattern\"\n" +
" dependentRequired:\n" +
" street:\n" +
" - country\n" +
" properties:\n" +
" street:\n" +
" type: string\n" +
" country:\n" +
" type: string\n" +
" enum:\n" +
" - UNITED_STATES_OF_AMERICA\n" +
" - CANADA\n" +
" propertyNames:\n" +
" pattern: \"^[A-Za-z_][A-Za-z0-9_]*$\"\n" +
"AnnotatedCountry:\n" +
" type: object\n" +
" properties:\n" +
" country:\n" +
" type: string\n" +
" const: United States\n" +
"Client:\n" +
" type: object\n" +
" properties:\n" +
" name:\n" +
" type: string\n" +
" creditCard:\n" +
" type: integer\n" +
" format: int32\n" +
"CreditCard:\n" +
" type: object\n" +
" properties:\n" +
" billingAddress:\n" +
" type: string\n" +
" acceptingCountries:\n" +
" type: array\n" +
" items:\n" +
" type: string\n" +
" description: accepting country\n" +
" enum:\n" +
" - UNITED_STATES_OF_AMERICA\n" +
" - CANADA\n" +
" uniqueItems: true\n" +
" availableCurrencies:\n" +
" type: array\n" +
" items:\n" +
" $ref: \"#/components/schemas/Currency\"\n" +
" description: available currencies\n" +
" uniqueItems: true\n" +
"Currency:\n" +
" type: object\n" +
" properties:\n" +
" currencyCode:\n" +
" type: string\n" +
"ModelWithOAS31Stuff:\n" +
" type: object\n" +
" $comment: Random comment at schema level\n" +
" $id: http://yourdomain.com/schemas/myschema.json\n" +
" description: this is model for testing OAS 3.1 resolving\n" +
" properties:\n" +
" randomList:\n" +
" type: array\n" +
" contains:\n" +
" type: string\n" +
" description: arraydescription\n" +
" items:\n" +
" type: string\n" +
" description: itemdescription\n" +
" title: itemtitle\n" +
" maxContains: 10\n" +
" minContains: 1\n" +
" prefixItems:\n" +
" - type: string\n" +
" title: arraytitle\n" +
" unevaluatedItems:\n" +
" type: number\n" +
" status:\n" +
" type:\n" +
" - string\n" +
" - number\n" +
" intValue:\n" +
" type: integer\n" +
" format: int32\n" +
" $anchor: intValue\n" +
" $comment: comment at schema property level\n" +
" exclusiveMaximum: 100\n" +
" exclusiveMinimum: 1\n" +
" text:\n" +
" type: string\n" +
" contentEncoding: plan/text\n" +
" contentMediaType: base64\n" +
" encodedString:\n" +
" type: string\n" +
" contentMediaType: application/jwt\n" +
" contentSchema:\n" +
" $ref: \"#/components/schemas/MultipleBaseBean\"\n" +
" address:\n" +
" $ref: \"#/components/schemas/Address\"\n" +
" client:\n" +
" $ref: \"#/components/schemas/Client\"\n" +
" dependentSchemas:\n" +
" creditCard:\n" +
" $ref: \"#/components/schemas/CreditCard\"\n" +
" patternProperties:\n" +
" creditCard:\n" +
" $ref: \"#/components/schemas/CreditCard\"\n" +
" properties:\n" +
" extraObject: {}\n" +
"MultipleBaseBean:\n" +
" type: object\n" +
" description: MultipleBaseBean\n" +
" properties:\n" +
" beanType:\n" +
" type: string\n" +
" a:\n" +
" type: integer\n" +
" format: int32\n" +
" b:\n" +
" type: string\n" +
"MultipleSub1Bean:\n" +
" allOf:\n" +
" - $ref: \"#/components/schemas/MultipleBaseBean\"\n" +
" - type: object\n" +
" properties:\n" +
" c:\n" +
" type: integer\n" +
" format: int32\n" +
" description: MultipleSub1Bean\n" +
"MultipleSub2Bean:\n" +
" allOf:\n" +
" - $ref: \"#/components/schemas/MultipleBaseBean\"\n" +
" - type: object\n" +
" properties:\n" +
" d:\n" +
" type: integer\n" +
" format: int32\n" +
" description: MultipleSub2Bean\n" +
"PostalCodeNumberPattern:\n" +
" type: object\n" +
" properties:\n" +
" postalCode:\n" +
" type: string\n" +
" pattern: \"[0-9]{5}(-[0-9]{4})?\"\n" +
"PostalCodePattern:\n" +
" type: object\n" +
" properties:\n" +
" postalCode:\n" +
" type: string\n" +
" pattern: \"[A-Z][0-9][A-Z] [0-9][A-Z][0-9]\"\n" +
"PropertyNamesPattern:\n" +
" pattern: \"^[A-Za-z_][A-Za-z0-9_]*$\"\n");
}
@Test
public void testDependentSchemasAnnotation() {
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema model = context.resolve(new AnnotatedType(ModelWithDependentSchema.class));
SerializationMatchers.assertEqualsToYaml31(context.getDefinedModels(), "BooleanFakeClass:\n" +
" type: object\n" +
" properties:\n" +
" type:\n" +
" type: boolean\n" +
"ModelWithDependentSchema:\n" +
" type: object\n" +
" dependentSchemas:\n" +
" value:\n" +
" properties:\n" +
" enable:\n" +
" $ref: \"#/components/schemas/BooleanFakeClass\"\n" +
" properties:\n" +
" name:\n" +
" type: string\n" +
" value:\n" +
" type: integer\n" +
" format: int32\n");
}
@Test(description = "Top level type:object should appear in OAS31")
public void testObjectTypeSchemaOAS31(){
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema model = context.resolve(new AnnotatedType(TestObject4715.class));
SerializationMatchers.assertEqualsToYaml31(model, "type: object\n" +
"properties:\n" +
" foo:\n" +
" type: string\n" +
" bar:\n" +
" type: string\n" +
" id:\n" +
" type: integer\n" +
" format: int32");
}
@Test
public void testFieldArraySchemaAnnotation() {
final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema model = context.resolve(new AnnotatedType(TestArrayType.class));
SerializationMatchers.assertEqualsToYaml31(model, " type: object\n" +
" properties:\n" +
" id:\n" +
" type: integer\n" +
" format: int32\n" +
" names:\n" +
" type: array\n" +
" items:\n" +
" type: string\n" +
" maxItems: 10");
}
@Test(description = "@Pattern correctly handled in type parameters of properties using collections when using oas 3.1.0")
public void testModelUsingCollectionTypePropertyHandlesPatternAnnotationForOas31() {
String expectedYaml = "ClassWithUsingPatternOnCollection:\n" +
" type: object\n" +
" properties:\n" +
" myField:\n" +
" type: array\n" +
" items:\n" +
" pattern: myPattern\n" +
" type: string";
Map<String, Schema> stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingPatternOnCollection.class);
SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml);
}
private static class ClassWithUsingPatternOnCollection {
private List<@Pattern(regexp = "myPattern") String> myField;
public List<String> getMyField() {
return myField;
}
public void setMyField(List<String> myField) {
this.myField = myField;
}
}
@Test(description = "@Size correctly handled in properties using collections when using oas 3.1.0")
public void testModelUsingCollectionTypePropertyHandleSizeAnnotationForOas31() {
String expectedYaml = "ClassWithUsingSizeOnCollection:\n" +
" type: object\n" +
" properties:\n" +
" myField:\n" +
" maxItems: 100\n" +
" minItems: 1\n" +
" type: array\n" +
" items:\n" +
" type: string";
Map<String, io.swagger.v3.oas.models.media.Schema> stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingSizeOnCollection.class);
SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml);
}
private static class ClassWithUsingSizeOnCollection {
@Size(min = 1, max = 100)
private List<String> myField;
public List<String> getMyField() {
return myField;
}
public void setMyField(List<String> myField) {
this.myField = myField;
}
}
@Test(description = "@Size correctly handled for field type String using OAS 3.1.0")
public void testSizeAnnotationOnFieldForOAS31() {
String expectedYaml = "ClassWithUsingSizeOnField:\n" +
" type: object\n" +
" properties:\n" +
" myField:\n" +
" type: string\n" +
" maxLength: 100\n" +
" minLength: 1";
Map<String, io.swagger.v3.oas.models.media.Schema> stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingSizeOnField.class);
SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml);
}
private static class ClassWithUsingSizeOnField {
@Size(min = 1, max = 100)
private String myField;
public String getMyField() {
return myField;
}
public void setMyField(String myField) {
this.myField = myField;
}
}
@Test(description = "@DecimalMax/Min annotations correctly handled for field type Number using OAS 3.1.0")
public void testDecimalAnnotationsOnField() {
String expectedYaml = "ClassWithUsingDecimalAnnotationsOnField:\n" +
" type: object\n" +
" properties:\n" +
" myField:\n" +
" type: number\n" +
" maximum: 100\n" +
" minimum: 1";
Map<String, io.swagger.v3.oas.models.media.Schema> stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingDecimalAnnotationsOnField.class);
SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml);
}
private static class ClassWithUsingDecimalAnnotationsOnField {
@DecimalMin("1")
@DecimalMax("100")
private Number myField;
public Number getMyField() {
return myField;
}
public void setMyField(Number myField) {
this.myField = myField;
}
}
}