diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/AbstractItemDeserializer.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/deserializers/ListDeserializer.java similarity index 70% rename from addOns/postman/src/main/java/org/zaproxy/addon/postman/AbstractItemDeserializer.java rename to addOns/postman/src/main/java/org/zaproxy/addon/postman/deserializers/ListDeserializer.java index 455c300ddba..2d6b4868268 100644 --- a/addOns/postman/src/main/java/org/zaproxy/addon/postman/AbstractItemDeserializer.java +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/deserializers/ListDeserializer.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.zaproxy.addon.postman; +package org.zaproxy.addon.postman.deserializers; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; @@ -28,14 +28,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.zaproxy.addon.postman.models.AbstractItem; +import org.zaproxy.addon.postman.models.AbstractListElement; -public class AbstractItemDeserializer extends JsonDeserializer> { +public class ListDeserializer extends JsonDeserializer> { private final ObjectMapper mapper = new ObjectMapper(); @Override - public List deserialize(JsonParser jsonParser, DeserializationContext ctxt) + public List deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException { JsonNode itemsNode = jsonParser.getCodec().readTree(jsonParser); @@ -48,10 +48,10 @@ public List deserialize(JsonParser jsonParser, DeserializationCont return List.of(); } - private List deserializeArray(JsonNode itemsNode) { - List items = new ArrayList(); + private List deserializeArray(JsonNode itemsNode) { + List items = new ArrayList(); for (JsonNode itemNode : itemsNode) { - AbstractItem item = deserializeItem(itemNode); + AbstractListElement item = deserializeItem(itemNode); if (item != null) { items.add(item); } @@ -59,14 +59,14 @@ private List deserializeArray(JsonNode itemsNode) { return Collections.unmodifiableList(items); } - private List deserializeObject(JsonNode itemNode) { - AbstractItem item = deserializeItem(itemNode); + private List deserializeObject(JsonNode itemNode) { + AbstractListElement item = deserializeItem(itemNode); return (item != null) ? List.of(item) : List.of(); } - private AbstractItem deserializeItem(JsonNode itemNode) { + private AbstractListElement deserializeItem(JsonNode itemNode) { try { - return mapper.treeToValue(itemNode, AbstractItem.class); + return mapper.treeToValue(itemNode, AbstractListElement.class); } catch (Exception e) { return null; } diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/deserializers/ObjectDeserializer.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/deserializers/ObjectDeserializer.java new file mode 100644 index 00000000000..d39f31111f9 --- /dev/null +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/deserializers/ObjectDeserializer.java @@ -0,0 +1,92 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zaproxy.addon.postman.deserializers; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.deser.ContextualDeserializer; +import com.fasterxml.jackson.databind.type.LogicalType; +import java.io.IOException; + +/** + * A custom JSON deserializer to ignore properties of an object when its signature doesn't match, + * rather than throwing an exception. + */ +public class ObjectDeserializer extends JsonDeserializer implements ContextualDeserializer { + + private final Class targetClass; + private final ObjectMapper mapper; + + public ObjectDeserializer() { + this(null); + } + + public ObjectDeserializer(Class targetClass) { + this.targetClass = targetClass; + this.mapper = new ObjectMapper(); + configureMapper(); + } + + private void configureMapper() { + mapper.coercionConfigFor(LogicalType.Textual) + .setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail); + } + + @Override + public JsonDeserializer createContextual( + final DeserializationContext deserializationContext, final BeanProperty beanProperty) + throws JsonMappingException { + // Determine target type + final Class targetClass; + { + final JavaType type; + if (beanProperty != null) { + type = beanProperty.getType(); + } else { + type = deserializationContext.getContextualType(); + } + targetClass = type.getRawClass(); + } + + return new ObjectDeserializer(targetClass); + } + + @Override + public Object deserialize(JsonParser jsonParser, DeserializationContext ctxt) + throws IOException { + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + + try { + return mapper.treeToValue(node, targetClass); + } catch (IOException e) { + return null; + } + } +} diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/AbstractItem.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/AbstractItem.java index df2aba79b38..d208b68fa1d 100644 --- a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/AbstractItem.java +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/AbstractItem.java @@ -26,4 +26,4 @@ @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) @JsonSubTypes({@JsonSubTypes.Type(Item.class), @JsonSubTypes.Type(ItemGroup.class)}) -public abstract class AbstractItem {} +public abstract class AbstractItem extends AbstractListElement {} diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/AbstractListElement.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/AbstractListElement.java new file mode 100644 index 00000000000..9ad953f00a4 --- /dev/null +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/AbstractListElement.java @@ -0,0 +1,29 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zaproxy.addon.postman.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) +@JsonSubTypes({@JsonSubTypes.Type(AbstractItem.class), @JsonSubTypes.Type(KeyValueData.class)}) +public abstract class AbstractListElement {} diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Body.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Body.java new file mode 100644 index 00000000000..e7f199b1810 --- /dev/null +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Body.java @@ -0,0 +1,215 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zaproxy.addon.postman.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.List; +import org.zaproxy.addon.postman.deserializers.ListDeserializer; +import org.zaproxy.addon.postman.deserializers.ObjectDeserializer; + +/** Represents the body of a request in the Postman format. */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Body { + + private static final List ALLOWED_MODES = + List.of("raw", "urlencoded", "formdata", "file", "graphql"); + + @JsonDeserialize(using = ObjectDeserializer.class) + private String mode; + + @JsonDeserialize(using = ObjectDeserializer.class) + private String raw; + + @JsonDeserialize(using = ListDeserializer.class) + private List urlencoded; + + @JsonDeserialize(using = ListDeserializer.class) + private List formData; + + @JsonDeserialize(using = ObjectDeserializer.class) + private File file; + + @JsonDeserialize(using = ObjectDeserializer.class) + private GraphQl graphQl; + + @JsonDeserialize(using = ObjectDeserializer.class) + private Options options; + + @JsonDeserialize(using = ObjectDeserializer.class) + private boolean disabled; + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + if (ALLOWED_MODES.contains(mode)) { + this.mode = mode; + } + } + + public String getRaw() { + return raw; + } + + public void setRaw(String raw) { + this.raw = raw; + } + + public List getUrlencoded() { + return urlencoded; + } + + public void setUrlencoded(List urlencoded) { + this.urlencoded = urlencoded; + } + + public List getFormData() { + return formData; + } + + public void setFormData(List formData) { + this.formData = formData; + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + + public GraphQl getGraphQl() { + return graphQl; + } + + public void setGraphQl(GraphQl graphQl) { + this.graphQl = graphQl; + } + + public Options getOptions() { + return options; + } + + public void setOptions(Options options) { + this.options = options; + } + + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class File { + @JsonDeserialize(using = ObjectDeserializer.class) + private String src; + + public String getSrc() { + return src; + } + + public void setSrc(String src) { + this.src = src; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class FormData extends KeyValueData { + @JsonDeserialize(using = ObjectDeserializer.class) + private String src; + + @JsonDeserialize(using = ObjectDeserializer.class) + private String type; + + public String getSrc() { + return src; + } + + public void setSrc(String src) { + this.src = src; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class GraphQl { + @JsonDeserialize(using = ObjectDeserializer.class) + private String query; + + @JsonDeserialize(using = ObjectDeserializer.class) + private String variables; + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public String getVariables() { + return variables; + } + + public void setVariables(String variables) { + this.variables = variables; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Options { + @JsonDeserialize(using = ObjectDeserializer.class) + private RawOption raw; + + public RawOption getRaw() { + return raw; + } + + public void setRaw(RawOption raw) { + this.raw = raw; + } + + public static class RawOption { + @JsonDeserialize(using = ObjectDeserializer.class) + private String language; + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + } + } +} diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Item.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Item.java index 86e32271f48..375ab177d6a 100644 --- a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Item.java +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Item.java @@ -20,6 +20,8 @@ package org.zaproxy.addon.postman.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.zaproxy.addon.postman.deserializers.ObjectDeserializer; /** * Represents an item in the Postman format which is the basic building block of a collection. @@ -28,13 +30,15 @@ */ @JsonIgnoreProperties(ignoreUnknown = true) public class Item extends AbstractItem { - private Object request; - public Object getRequest() { + @JsonDeserialize(using = ObjectDeserializer.class) + private Request request; + + public Request getRequest() { return request; } - public void setRequest(Object request) { + public void setRequest(Request request) { this.request = request; } } diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/ItemGroup.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/ItemGroup.java index ee2859d9839..91ba1d292cf 100644 --- a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/ItemGroup.java +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/ItemGroup.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.util.List; -import org.zaproxy.addon.postman.AbstractItemDeserializer; +import org.zaproxy.addon.postman.deserializers.ListDeserializer; /** * Represents an item-group in the Postman format which can contain both item and item-group @@ -32,7 +32,7 @@ */ @JsonIgnoreProperties(ignoreUnknown = true) public class ItemGroup extends AbstractItem { - @JsonDeserialize(using = AbstractItemDeserializer.class) + @JsonDeserialize(using = ListDeserializer.class) private List item; public List getItem() { diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/KeyValueData.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/KeyValueData.java new file mode 100644 index 00000000000..be1f6d614d7 --- /dev/null +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/KeyValueData.java @@ -0,0 +1,60 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zaproxy.addon.postman.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.zaproxy.addon.postman.deserializers.ObjectDeserializer; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class KeyValueData extends AbstractListElement { + @JsonDeserialize(using = ObjectDeserializer.class) + private String key; + + @JsonDeserialize(using = ObjectDeserializer.class) + private String value; + + @JsonDeserialize(using = ObjectDeserializer.class) + private Boolean disabled; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Boolean isDisabled() { + return disabled; + } + + public void setDisabled(Boolean disabled) { + this.disabled = disabled; + } +} diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/PostmanCollection.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/PostmanCollection.java index 5e89a97f893..bb41038209d 100644 --- a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/PostmanCollection.java +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/PostmanCollection.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.util.List; -import org.zaproxy.addon.postman.AbstractItemDeserializer; +import org.zaproxy.addon.postman.deserializers.ListDeserializer; /** * Represents a collection in the Postman format. @@ -32,7 +32,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class PostmanCollection { - @JsonDeserialize(using = AbstractItemDeserializer.class) + @JsonDeserialize(using = ListDeserializer.class) private List item; private Object variable; diff --git a/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Request.java b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Request.java new file mode 100644 index 00000000000..82907d7f16c --- /dev/null +++ b/addOns/postman/src/main/java/org/zaproxy/addon/postman/models/Request.java @@ -0,0 +1,107 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zaproxy.addon.postman.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.List; +import org.parosproxy.paros.network.HttpRequestHeader; +import org.zaproxy.addon.postman.deserializers.ListDeserializer; +import org.zaproxy.addon.postman.deserializers.ObjectDeserializer; + +/** + * Represents the request in the Postman format which is contained by the items. + * + * @see https://learning.postman.com/collection-format/reference/request/ + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Request { + + @JsonDeserialize(using = ObjectDeserializer.class) + private Url url; + + @JsonDeserialize(using = ObjectDeserializer.class) + private String method = HttpRequestHeader.GET; + + @JsonDeserialize(using = ListDeserializer.class) + private List header; + + @JsonDeserialize(using = ObjectDeserializer.class) + private Body body; + + public Request() {} + + public Request(String url) { + this.url = new Url(url); + } + + public Url getUrl() { + return url; + } + + public void setUrl(Url url) { + this.url = url; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public List getHeader() { + return header; + } + + public void setHeader(List header) { + this.header = header; + } + + public Body getBody() { + return body; + } + + public void setBody(Body body) { + this.body = body; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Url { + + @JsonDeserialize(using = ObjectDeserializer.class) + private String raw; + + public Url() {} + + public Url(String raw) { + this.raw = raw; + } + + public String getRaw() { + return raw; + } + + public void setRaw(String raw) { + this.raw = raw; + } + } +} diff --git a/addOns/postman/src/test/java/org/zaproxy/addon/postman/AbstractItemDeserializerUnitTest.java b/addOns/postman/src/test/java/org/zaproxy/addon/postman/ListDeserializerUnitTest.java similarity index 97% rename from addOns/postman/src/test/java/org/zaproxy/addon/postman/AbstractItemDeserializerUnitTest.java rename to addOns/postman/src/test/java/org/zaproxy/addon/postman/ListDeserializerUnitTest.java index 7b716759a5a..646e031eb79 100644 --- a/addOns/postman/src/test/java/org/zaproxy/addon/postman/AbstractItemDeserializerUnitTest.java +++ b/addOns/postman/src/test/java/org/zaproxy/addon/postman/ListDeserializerUnitTest.java @@ -32,7 +32,7 @@ import org.zaproxy.addon.postman.models.PostmanCollection; import org.zaproxy.zap.testutils.TestUtils; -class AbstractItemDeserializerUnitTest extends TestUtils { +class ListDeserializerUnitTest extends TestUtils { @BeforeEach void setup() throws Exception { diff --git a/addOns/postman/src/test/java/org/zaproxy/addon/postman/ObjectDeserializerUnitTest.java b/addOns/postman/src/test/java/org/zaproxy/addon/postman/ObjectDeserializerUnitTest.java new file mode 100644 index 00000000000..feac551f9cf --- /dev/null +++ b/addOns/postman/src/test/java/org/zaproxy/addon/postman/ObjectDeserializerUnitTest.java @@ -0,0 +1,72 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zaproxy.addon.postman; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.zaproxy.addon.postman.models.Item; +import org.zaproxy.addon.postman.models.PostmanCollection; +import org.zaproxy.addon.postman.models.Request.Url; +import org.zaproxy.zap.testutils.TestUtils; + +class ObjectDeserializerUnitTest extends TestUtils { + + @BeforeEach + void setup() throws Exception { + setUpZap(); + } + + static Object[][] deserializationTestData() { + return new Object[][] { + {"{\"item\":{\"request\":{\"url\":{\"raw\":\"https://example.com\"}}}}"}, + {"{\"item\":{\"request\":{\"url\":\"https://example.com\"}}}"} + }; + } + + @ParameterizedTest + @MethodSource("deserializationTestData") + void shouldDeserializeObject(String defn) throws Exception { + PostmanParser parser = new PostmanParser(); + PostmanCollection collection = parser.parse(defn); + + Url url = ((Item) collection.getItem().get(0)).getRequest().getUrl(); + assertNotNull(url); + + String raw = url.getRaw(); + assertNotNull(raw); + assertEquals(raw, "https://example.com"); + } + + @Test + void shouldDeserializeInvalidObjectSilently() throws Exception { + PostmanParser parser = new PostmanParser(); + String defn = "{\"item\":{\"request\":{\"url\":true}}}}"; + + PostmanCollection collection = assertDoesNotThrow(() -> parser.parse(defn)); + assertNull(((Item) collection.getItem().get(0)).getRequest().getUrl()); + } +}