package io.swagger; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.converter.ModelConverters; import io.swagger.matchers.SerializationMatchers; import io.swagger.models.ArrayModel; import io.swagger.models.Car; import io.swagger.models.ExternalDocs; import io.swagger.models.Manufacturers; import io.swagger.models.Model; import io.swagger.models.ModelImpl; import io.swagger.models.RefModel; import io.swagger.models.properties.DateProperty; import io.swagger.models.properties.DateTimeProperty; import io.swagger.models.properties.IntegerProperty; import io.swagger.models.properties.LongProperty; import io.swagger.models.properties.Property; import io.swagger.models.properties.RefProperty; import io.swagger.models.properties.StringProperty; import io.swagger.util.Json; import org.testng.annotations.Test; import java.io.IOException; import java.math.BigDecimal; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; public class ModelSerializerTest { private final ObjectMapper m = Json.mapper(); @Test(description = "it should convert a model") public void convertModel() throws JsonProcessingException { final ModelImpl pet = new ModelImpl(); final HashMap<String, Property> props = new HashMap<String, Property>(); props.put("intValue", new IntegerProperty()); props.put("longValue", new LongProperty()); props.put("dateValue", new DateProperty()); props.put("dateTimeValue", new DateTimeProperty()); pet.setProperties(props); pet.setRequired(Arrays.asList("intValue", "name")); final String json = "{\n" + " \"required\":[\n" + " \"intValue\"\n" + " ],\n" + " \"properties\":{\n" + " \"dateValue\":{\n" + " \"type\":\"string\",\n" + " \"format\":\"date\"\n" + " },\n" + " \"longValue\":{\n" + " \"type\":\"integer\",\n" + " \"format\":\"int64\"\n" + " },\n" + " \"dateTimeValue\":{\n" + " \"type\":\"string\",\n" + " \"format\":\"date-time\"\n" + " },\n" + " \"intValue\":{\n" + " \"type\":\"integer\",\n" + " \"format\":\"int32\"\n" + " }\n" + " }\n" + "}"; SerializationMatchers.assertEqualsToJson(pet, json); } @Test(description = "it should deserialize a model") public void deserializeModel() throws IOException { final String json = "{\n" + " \"required\":[\n" + " \"intValue\"\n" + " ],\n" + " \"properties\":{\n" + " \"dateValue\":{\n" + " \"type\":\"string\",\n" + " \"format\":\"date\"\n" + " },\n" + " \"longValue\":{\n" + " \"type\":\"integer\",\n" + " \"format\":\"int64\"\n" + " },\n" + " \"dateTimeValue\":{\n" + " \"type\":\"string\",\n" + " \"format\":\"date-time\"\n" + " },\n" + " \"intValue\":{\n" + " \"type\":\"integer\",\n" + " \"format\":\"int32\"\n" + " },\n" + " \"byteArrayValue\":{\n" + " \"type\":\"string\",\n" + " \"format\":\"binary\"\n" + " }\n" + " }\n" + "}"; final Model p = m.readValue(json, Model.class); SerializationMatchers.assertEqualsToJson(p, json); } @Test(description = "it should serialize an array model") public void serializeArrayModel() throws IOException { final ArrayModel model = new ArrayModel(); model.setItems(new RefProperty("Pet")); assertEquals(m.writeValueAsString(model), "{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/Pet\"}}"); } @Test(description = "it should deserialize an array model") public void deserializeArrayModel() throws IOException { final String json = "{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/Pet\"}}"; final Model p = m.readValue(json, Model.class); assertTrue(p instanceof ArrayModel); assertEquals(m.writeValueAsString(p), json); } @Test(description = "it should not create an xml object for ref") public void shouldNotCreateXmlObjectForRef() throws IOException { final RefModel model = new RefModel("Monster"); model.setDescription("oops"); model.setExternalDocs(new ExternalDocs("external docs", "http://swagger.io")); assertEquals(Json.mapper().writeValueAsString(model), "{\"$ref\":\"#/definitions/Monster\"}"); } @Test(description = "it should make a field readOnly by annotation") public void makeFieldReadOnly() throws IOException { final Map<String, Model> schemas = ModelConverters.getInstance().read(Car.class); final String json = "{\n" + " \"Car\":{\n" + " \"type\":\"object\",\n" + " \"properties\":{\n" + " \"wheelCount\":{\n" + " \"type\":\"integer\",\n" + " \"format\":\"int32\",\n" + " \"readOnly\":true\n" + " }\n" + " }\n" + " }\n" + "}"; SerializationMatchers.assertEqualsToJson(schemas, json); } @Test(description = "it should serialize a model with a Set") public void serializeModelWithSet() throws IOException { final Map<String, Model> schemas = ModelConverters.getInstance().read(Manufacturers.class); final String json = "{\n" + " \"Manufacturers\":{\n" + " \"type\":\"object\",\n" + " \"properties\":{\n" + " \"countries\":{\n" + " \"type\":\"array\",\n" + " \"uniqueItems\":true,\n" + " \"items\":{\n" + " \"type\":\"string\"\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"; SerializationMatchers.assertEqualsToJson(schemas, json); } @Test(description = "it should deserialize a model with object example") public void deserializeModelWithObjectExample() throws IOException { final String json = "{\n" + " \"title\":\"Error\",\n" + " \"type\":\"object\",\n" + " \"properties\":{\n" + " \"code\":{\n" + " \"type\":\"integer\",\n" + " \"format\":\"int32\"\n" + " },\n" + " \"message\":{\n" + " \"type\":\"string\"\n" + " },\n" + " \"fields\":{\n" + " \"type\":\"string\"\n" + " }\n" + " },\n" + " \"example\":{\n" + " \"code\":1,\n" + " \"message\":\"hello\",\n" + " \"fields\":\"abc\"\n" + " }\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); assertEquals(Json.mapper().writeValueAsString(model.getExample()), "{\"code\":1,\"message\":\"hello\",\"fields\":\"abc\"}"); } @Test(description = "it should deserialize a model with read-only property") public void deserializeModelWithReadOnlyProperty() throws IOException { final String json = "{\n" + " \"properties\":{\n" + " \"id\":{\n" + " \"type\":\"integer\",\n" + " \"format\":\"int32\",\n" + " \"readOnly\":true\n" + " }\n" + " }\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); Property property = model.getProperties().get("id"); assertTrue(property.getReadOnly()); } /* @Test(description = "it should deserialize a model with custom format") public void deserializeModelWithCustomFormat() throws IOException { final String json = "{\n" + " \"properties\":{\n" + " \"id\":{\n" + " \"type\":\"string\",\n" + " \"format\":\"custom\"\n" + " }\n" + " }\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); Json.prettyPrint(model); }*/ @Test(description = "it should generate a JSON with read-only from pojo, #1161") public void readOnlyJsonGeneration() throws IOException { Map<String, Model> models = ModelConverters.getInstance().read(io.swagger.models.ReadOnlyModel.class); Model model = models.get("ReadOnlyModel"); Property id = model.getProperties().get("id"); assertTrue(id.getReadOnly()); Property readWriteId = model.getProperties().get("readWriteId"); assertNull(readWriteId.getReadOnly()); } @Test(description = "it should generate an integer field with enum") public void integerEnumGeneration() throws IOException { final String json = "{\n" + " \"properties\":{\n" + " \"id\":{\n" + " \"description\":\"fun!\",\n" + " \"type\":\"integer\",\n" + " \"format\":\"int32\",\n" + " \"readOnly\":true,\n" + " \"enum\": [ 0, 1]\n" + " }\n" + " }\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); IntegerProperty p = (IntegerProperty)model.getProperties().get("id"); assertNotNull(p.getEnum()); assertEquals(p.getEnum().get(0), new Integer(0)); assertEquals(p.getEnum().get(1), new Integer(1)); } @Test(description = "it retains enums per ") public void testEnumParser() throws IOException { String json = "{\n" + " \"properties\": {\n" + " \"AdvStateType\": {\n" + " \"description\": \"Advertising State\",\n" + " \"enum\": [\n" + " \"off\",\n" + " \"on\"\n" + " ],\n" + " \"type\": \"string\"\n" + " }\n" + " }\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); StringProperty p = (StringProperty)model.getProperties().get("AdvStateType"); assertNotNull(p.getEnum()); assertEquals(p.getEnum().get(0), "off"); assertEquals(p.getEnum().get(1), "on"); } @Test public void testPrimitiveModel() throws Exception { String json = "{\n" + " \"type\": \"string\",\n" + " \"enum\": [\n" + " \"a\",\n" + " \"b\",\n" + " \"c\"\n" + " ]\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); assertNotNull(model.getEnum()); assertTrue(model.getEnum().size() == 3); } @Test public void testIssue1852() throws Exception { String json = "{\n" + " \"type\": \"integer\",\n" + " \"minimum\": 10,\n" + " \"maximum\": 20,\n" + " \"default\": 15\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); assertEquals(model.getMinimum().intValue(), 10); assertEquals(model.getMaximum().intValue(), 20); assertEquals(model.getDefaultValue(), 15); } @Test public void testIssue2064Neg() throws Exception { String json = "{\n" + " \"type\": \"string\",\n" + " \"uniqueItems\": false\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); assertFalse(model.getUniqueItems()); } @Test public void testIssue2064() throws Exception { String json = "{\n" + " \"type\": \"string\",\n" + " \"uniqueItems\": true\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); assertTrue(model.getUniqueItems()); } @Test public void testIssue2064Ip() throws Exception { String json = "{\n" + " \"type\": \"object\",\n" + " \"properties\": {\n" + " \"id\": {\n" + " \"type\": \"integer\",\n" + " \"format\": \"int32\",\n" + " \"multipleOf\": 3.0\n" + " }\n" + " }\n" + "}"; final ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); IntegerProperty ip = (IntegerProperty) model.getProperties().get("id"); assertEquals(ip.getMultipleOf(), new BigDecimal("3.0")); } }