diff --git a/README.md b/README.md index 32301cf52..75640bf19 100644 --- a/README.md +++ b/README.md @@ -89,9 +89,11 @@ Usage example: ``` .filter(new AllureRestAssured()) ``` -You can specify custom templateName: +You can specify custom templates, which should be placed in src/main/resources/tpl folder: ``` -.filter(new AllureRestAssured().withTemplate("/templates/custom_template.ftl")) +.filter(new AllureRestAssured() + .withRequestTemplate("custom-http-request.ftl") + .withResponseTemplate("custom-http-response.ftl")) ``` ## OkHttp @@ -136,3 +138,13 @@ Usage example: .addInterceptorLast(new AllureHttpClientResponse()); ``` +## JsonUnit +JsonPatchMatcher is extension of JsonUnit matcher, that generates pretty html attachment for differences based on [json diff patch](https://github.com/benjamine/jsondiffpatch/blob/master/docs/deltas.md). + +```xml + + io.qameta.allure + allure-jsonunit + $LATEST_VERSION + +``` \ No newline at end of file diff --git a/allure-jsonunit/build.gradle b/allure-jsonunit/build.gradle new file mode 100644 index 000000000..383fd829f --- /dev/null +++ b/allure-jsonunit/build.gradle @@ -0,0 +1,13 @@ +description = 'Allure JsonUnit' + +apply from: "${gradleScriptDir}/maven-publish.gradle" +apply from: "${gradleScriptDir}/bintray.gradle" +apply plugin: 'maven' + +dependencies { + compile project(':allure-attachments') + compile('net.javacrumbs.json-unit:json-unit:2.0.0.RC1') + + testCompile('junit:junit') + testCompile('org.hamcrest:hamcrest-library') +} diff --git a/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/AllureConfigurableJsonMatcher.java b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/AllureConfigurableJsonMatcher.java new file mode 100644 index 000000000..75cbd4020 --- /dev/null +++ b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/AllureConfigurableJsonMatcher.java @@ -0,0 +1,26 @@ +package io.qameta.allure.jsonunit; + +import net.javacrumbs.jsonunit.core.Option; +import net.javacrumbs.jsonunit.core.internal.Options; +import org.hamcrest.Matcher; + +import java.math.BigDecimal; + +/** + * @param the type of matcher + * @see net.javacrumbs.jsonunit.ConfigurableJsonMatcher + */ +public interface AllureConfigurableJsonMatcher extends Matcher { + + AllureConfigurableJsonMatcher withTolerance(BigDecimal tolerance); + + AllureConfigurableJsonMatcher withTolerance(double tolerance); + + AllureConfigurableJsonMatcher when(Option first, Option... next); + + AllureConfigurableJsonMatcher withOptions(Options options); + + AllureConfigurableJsonMatcher withMatcher(String matcherName, Matcher matcher); + + AllureConfigurableJsonMatcher whenIgnoringPaths(String... paths); +} diff --git a/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/DiffAttachment.java b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/DiffAttachment.java new file mode 100644 index 000000000..5af031a61 --- /dev/null +++ b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/DiffAttachment.java @@ -0,0 +1,36 @@ +package io.qameta.allure.jsonunit; + +import io.qameta.allure.attachment.AttachmentData; + +/** + * @author Victor Orlovsky + */ +public class DiffAttachment implements AttachmentData { + + private final String patch; + private final String actual; + private final String expected; + + public DiffAttachment(final String actual, final String expected, final String patch) { + this.actual = actual; + this.expected = expected; + this.patch = patch; + } + + public String getPatch() { + return patch; + } + + public String getActual() { + return actual; + } + + public String getExpected() { + return expected; + } + + @Override + public String getName() { + return "JSON difference"; + } +} diff --git a/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/JsonPatchListener.java b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/JsonPatchListener.java new file mode 100644 index 000000000..77dd38dfa --- /dev/null +++ b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/JsonPatchListener.java @@ -0,0 +1,144 @@ +package io.qameta.allure.jsonunit; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.javacrumbs.jsonunit.core.listener.Difference; +import net.javacrumbs.jsonunit.core.listener.DifferenceContext; +import net.javacrumbs.jsonunit.core.listener.DifferenceListener; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * JsonUnit listener, that keeps difference and + * return formatted json to represent deltas + * (i.e. the output of jsondiffpatch.diff). + */ +public class JsonPatchListener implements DifferenceListener { + + private static final String UNKNOWN_TYPE_ERROR = "Difference has unknown type"; + private final List differences = new ArrayList<>(); + + private DifferenceContext context; + + @Override + public void diff(final Difference difference, final DifferenceContext differenceContext) { + this.context = differenceContext; + differences.add(difference); + } + + public List getDifferences() { + return differences; + } + + public DifferenceContext getContext() { + return context; + } + + @SuppressWarnings("ReturnCount") + private String getPath(final Difference difference) { + switch (difference.getType()) { + case DIFFERENT: + return difference.getActualPath(); + + case MISSING: + return difference.getExpectedPath(); + + case EXTRA: + return difference.getActualPath(); + + default: + throw new IllegalArgumentException(UNKNOWN_TYPE_ERROR); + } + } + + @SuppressWarnings("ReturnCount") + private List getPatch(final Difference difference) { + final List result = new ArrayList<>(); + + switch (difference.getType()) { + case DIFFERENT: + result.add(difference.getExpected()); + result.add(difference.getActual()); + return result; + + case MISSING: + result.add(difference.getExpected()); + result.add(0); + result.add(0); + return result; + + case EXTRA: + result.add(difference.getActual()); + return result; + + default: + throw new IllegalArgumentException(UNKNOWN_TYPE_ERROR); + } + } + + @SuppressWarnings({"all", "unchecked"}) + public String getJsonPatch() { + final Map jsonDiffPatch = new HashMap<>(); + // take care of corner case when two jsons absolutelly different + if (getDifferences().size() == 1) { + final Difference difference = getDifferences().get(0); + final String field = getPath(difference); + if (field.isEmpty()) { + final ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.writeValueAsString(getPatch(difference)); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Could not process patch json", e); + } + } + } + getDifferences().forEach(difference -> { + + final String field = getPath(difference); + Map currentMap = jsonDiffPatch; + + final String fieldWithDots = StringUtils.replace(field, "[", "."); + final int len = fieldWithDots.length(); + int left = 0; + int right = 0; + while (left < len) { + right = fieldWithDots.indexOf('.', left); + if (right == -1) { + right = len; + } + String fieldName = fieldWithDots.substring(left, right); + fieldName = StringUtils.remove(fieldName, "]"); + + if (right != len) { + if (!fieldName.isEmpty()) { + if (!currentMap.containsKey(fieldName)) { + currentMap.put(fieldName, new HashMap<>()); + } + currentMap = (Map) currentMap.get(fieldName); + } + + if (field.charAt(right) == '[') { + if (!currentMap.containsKey(fieldName)) { + currentMap.put("_t", "a"); + } + } + } else { + final List actualExpectedValue = getPatch(difference); + currentMap.put(fieldName, actualExpectedValue); + } + left = right + 1; + } + }); + + final ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.writeValueAsString(jsonDiffPatch); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Could not process patch json", e); + } + } +} diff --git a/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/JsonPatchMatcher.java b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/JsonPatchMatcher.java new file mode 100644 index 000000000..122b5504b --- /dev/null +++ b/allure-jsonunit/src/main/java/io/qameta/allure/jsonunit/JsonPatchMatcher.java @@ -0,0 +1,106 @@ +package io.qameta.allure.jsonunit; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.qameta.allure.attachment.DefaultAttachmentProcessor; +import io.qameta.allure.attachment.FreemarkerAttachmentRenderer; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import net.javacrumbs.jsonunit.core.internal.Diff; +import net.javacrumbs.jsonunit.core.internal.Options; +import org.hamcrest.Description; +import org.hamcrest.Matcher; + +import java.math.BigDecimal; + +/** + * JsonPatchMatcher is extension of JsonUnit matcher, + * that generates pretty html attachment for differences. + * @param the type + */ +public final class JsonPatchMatcher implements AllureConfigurableJsonMatcher { + private static final String EMPTY_PATH = ""; + private static final String FULL_JSON = "fullJson"; + private Configuration configuration = Configuration.empty(); + private final Object expected; + private String differences; + + private JsonPatchMatcher(final Object expected) { + this.expected = expected; + } + + public static AllureConfigurableJsonMatcher jsonEquals(final Object expected) { + return new JsonPatchMatcher(expected); + } + + public AllureConfigurableJsonMatcher withTolerance(final BigDecimal tolerance) { + configuration = configuration.withTolerance(tolerance); + return this; + } + + public AllureConfigurableJsonMatcher withTolerance(final double tolerance) { + configuration = configuration.withTolerance(tolerance); + return this; + } + + public AllureConfigurableJsonMatcher when(final Option first, final Option... next) { + configuration = configuration.when(first, next); + return this; + } + + public AllureConfigurableJsonMatcher withOptions(final Options options) { + configuration = configuration.withOptions(options); + return this; + } + + public AllureConfigurableJsonMatcher withMatcher(final String matcherName, final Matcher matcher) { + configuration = configuration.withMatcher(matcherName, matcher); + return this; + } + + public AllureConfigurableJsonMatcher whenIgnoringPaths(final String... paths) { + configuration = configuration.whenIgnoringPaths(paths); + return this; + } + + private void render(final JsonPatchListener listener) { + final ObjectMapper mapper = new ObjectMapper(); + final String patch = listener.getJsonPatch(); + try { + final String actual = mapper.writeValueAsString(listener.getContext().getActualSource()); + final String expected = mapper.writeValueAsString(listener.getContext().getExpectedSource()); + final DiffAttachment attachment = new DiffAttachment(actual, expected, patch); + new DefaultAttachmentProcessor().addAttachment(attachment, + new FreemarkerAttachmentRenderer("diff.ftl")); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Could not process actual/expected json", e); + } + } + + @Override + public boolean matches(final Object actual) { + final JsonPatchListener listener = new JsonPatchListener(); + final Diff diff = Diff.create(expected, actual, FULL_JSON, EMPTY_PATH, + configuration.withDifferenceListener(listener)); + if (!diff.similar()) { + differences = diff.differences(); + render(listener); + } + return diff.similar(); + } + + public void describeTo(final Description description) { + description.appendText("has no difference"); + } + + @Override + public void describeMismatch(final Object item, final Description description) { + description.appendText(differences); + } + + @SuppressWarnings("deprecation") + @Override + public void _dont_implement_Matcher___instead_extend_BaseMatcher_() { + //do nothing + } +} diff --git a/allure-jsonunit/src/main/resources/tpl/diff.ftl b/allure-jsonunit/src/main/resources/tpl/diff.ftl new file mode 100644 index 000000000..478c29f5f --- /dev/null +++ b/allure-jsonunit/src/main/resources/tpl/diff.ftl @@ -0,0 +1,171 @@ + + + +<#--https://cdn.jsdelivr.net/npm/jsondiffpatch/dist/jsondiffpatch.umd.min.js--> + + +<#--https://github.com/benjamine/jsondiffpatch/blob/master/docs/formatters-styles/html.css--> + + +
+ + + \ No newline at end of file diff --git a/allure-jsonunit/src/test/java/io/qameta/allure/jsonunit/JsonPatchListenerTest.java b/allure-jsonunit/src/test/java/io/qameta/allure/jsonunit/JsonPatchListenerTest.java new file mode 100644 index 000000000..f179c6839 --- /dev/null +++ b/allure-jsonunit/src/test/java/io/qameta/allure/jsonunit/JsonPatchListenerTest.java @@ -0,0 +1,172 @@ +package io.qameta.allure.jsonunit; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import net.javacrumbs.jsonunit.core.internal.Diff; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +public class JsonPatchListenerTest { + + private final JsonPatchListener listener = new JsonPatchListener(); + + @Test + public void shouldSeeEmptyDiffNodes() { + Diff diff = Diff.create("{}", "{}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getDifferences(), hasSize(0)); + } + + @Test + public void shouldSeeRemovedNode() { + Diff diff = Diff.create("{\"test\": \"1\"}", "{}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"test\":[\"1\",0,0]}")); + } + + @Test + public void shouldSeeAddedNode() { + Diff diff = Diff.create("{}", "{\"test\": \"1\"}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"test\":[\"1\"]}")); + } + + @Test + public void shouldSeeEmptyForCheckAnyNode() { + Diff diff = Diff.create("{\"test\": \"${json-unit.ignore}\"}", "{\"test\":\"1\"}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{}")); + } + + @Test + public void shouldSeeEmptyForCheckAnyBooleanNode() { + Diff diff = Diff.create("{\"test\": \"${json-unit.any-boolean}\"}", "{\"test\": true}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{}")); + } + + @Test + public void shouldSeeEmptyForCheckAnyNumberNode() { + Diff diff = Diff.create("{\"test\": \"${json-unit.any-number}\"}", "{\"test\": 11}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{}")); + + } + + @Test + public void shouldSeeEmptyForCheckAnyStringNode() { + Diff diff = Diff.create("{\"test\": \"${json-unit.any-string}\"}", "{\"test\": \"1\"}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{}")); + } + + + @Test + public void shouldSeeChangedStringNode() { + Diff diff = Diff.create("{\"test\": \"1\"}", "{\"test\": \"2\"}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"test\":[\"1\",\"2\"]}")); + } + + @Test + public void shouldSeeChangedNumberNode() { + Diff diff = Diff.create("{\"test\": 1}", "{\"test\": 2 }", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"test\":[1,2]}")); + + } + + @Test + public void shouldSeeChangedBooleanNode() { + Diff diff = Diff.create("{\"test\": true}", "{\"test\": false}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"test\":[true,false]}")); + } + + @Test + public void shouldSeeChangedStructureNode() { + Diff diff = Diff.create("{\"test\": \"1\"}", "{\"test\": false}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"test\":[\"1\",false]}")); + } + + @Test + public void shouldSeeChangedArrayNode() { + Diff diff = Diff.create("[1, 1]", "[1, 2]", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"1\":[1,2],\"_t\":\"a\"}")); + } + + @Test + public void shouldSeeRemovedArrayNode() { + Diff diff = Diff.create("[1, 2]", "[1]", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"1\":[2,0,0],\"_t\":\"a\"}")); + } + + @Test + public void shouldSeeAddedArrayNode() { + Diff diff = Diff.create("[1]", "[1, 2]", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"1\":[2],\"_t\":\"a\"}")); + } + + @Test + public void shouldSeeObjectDiffNodes() { + Diff diff = Diff.create("{\"test\": { \"test1\": \"1\"}}", "{\"test\": { \"test1\": \"2\"} }", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{\"test\":{\"test1\":[\"1\",\"2\"]}}")); + } + + @Test + public void shouldSeeNullNode() { + Diff diff = Diff.create(null, null, "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("{}")); + } + + @Test + public void shouldWorkWhenIgnoringArrayOrder() { + Diff diff = Diff.create("{\"test\": [[1,2],[2,3]]}", "{\"test\":[[4,2],[1,2]]}", "", "", commonConfig().when(Option.IGNORING_ARRAY_ORDER)); + diff.similar(); + assertThat(listener.getJsonPatch(), + equalTo("{\"test\":{\"0\":{\"0\":[3,4],\"_t\":\"a\"},\"_t\":\"a\"}}")); + } + + @Test + public void shouldSeeActualSource() throws JsonProcessingException { + Diff diff = Diff.create("{\"test\": \"1\"}", "{}", "", "", commonConfig()); + diff.similar(); + assertThat(new ObjectMapper().writeValueAsString(listener.getContext().getActualSource()), equalTo("{}")); + } + + @Test + public void shouldSeeExpectedSource() throws JsonProcessingException { + Diff diff = Diff.create("{\"test\": \"1\"}", "{}", "", "", commonConfig()); + diff.similar(); + assertThat(new ObjectMapper().writeValueAsString(listener.getContext().getExpectedSource()), equalTo("{\"test\":\"1\"}")); + } + + @Test + public void shouldSeeNodeChangeToArray() { + Diff diff = Diff.create("{\"test\": \"1\"}", "[[1,2],[2,3],[1,1]]", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("[{\"test\":\"1\"},[[1,2],[2,3],[1,1]]]")); + } + + @Test + public void shouldArrayChangeToNode() { + Diff diff = Diff.create("[[1,2],[2,3],[1,1]]", "{\"test\": \"1\"}", "", "", commonConfig()); + diff.similar(); + assertThat(listener.getJsonPatch(), equalTo("[[[1,2],[2,3],[1,1]],{\"test\":\"1\"}]")); + } + + private Configuration commonConfig() { + return Configuration.empty().withDifferenceListener(listener); + } +} diff --git a/allure-rest-assured/src/main/java/io/qameta/allure/restassured/AllureRestAssured.java b/allure-rest-assured/src/main/java/io/qameta/allure/restassured/AllureRestAssured.java index 9b30a684e..c36329fe2 100644 --- a/allure-rest-assured/src/main/java/io/qameta/allure/restassured/AllureRestAssured.java +++ b/allure-rest-assured/src/main/java/io/qameta/allure/restassured/AllureRestAssured.java @@ -24,6 +24,9 @@ */ public class AllureRestAssured implements OrderedFilter { + private String requestTemplatePath = "http-request.ftl"; + private String responseTemplatePath = "http-response.ftl"; + @Override public Response filter(final FilterableRequestSpecification requestSpec, final FilterableResponseSpecification responseSpec, @@ -44,7 +47,7 @@ public Response filter(final FilterableRequestSpecification requestSpec, new DefaultAttachmentProcessor().addAttachment( requestAttachment, - new FreemarkerAttachmentRenderer("http-request.ftl") + new FreemarkerAttachmentRenderer(requestTemplatePath) ); final Response response = filterContext.next(requestSpec, responseSpec); @@ -56,7 +59,7 @@ public Response filter(final FilterableRequestSpecification requestSpec, new DefaultAttachmentProcessor().addAttachment( responseAttachment, - new FreemarkerAttachmentRenderer("http-response.ftl") + new FreemarkerAttachmentRenderer(responseTemplatePath) ); return response; @@ -68,6 +71,16 @@ private static Map toMapConverter(final Iterable dependency 'org.assertj:assertj-core:3.10.0' dependency 'org.codehaus.groovy:groovy-all:2.5.0' dependency 'org.freemarker:freemarker:2.3.28' + dependency 'org.hamcrest:hamcrest-library:1.3' dependency 'org.jbehave:jbehave-core:4.3.4' dependency 'org.jooq:joor-java-8:0.9.9' dependency 'org.junit.jupiter:junit-jupiter-api:5.2.0' @@ -98,6 +99,7 @@ subprojects { project -> dependency 'org.springframework:spring-test:4.3.18.RELEASE' dependency 'org.springframework:spring-webmvc:4.3.18.RELEASE' dependency 'org.testng:testng:6.14.3' + dependency 'net.javacrumbs.json-unit:json-unit:2.0.0.RC1' } } diff --git a/examples/jsonunit-patch-listener/build.gradle b/examples/jsonunit-patch-listener/build.gradle new file mode 100644 index 000000000..06531789d --- /dev/null +++ b/examples/jsonunit-patch-listener/build.gradle @@ -0,0 +1,30 @@ +description = 'Allure JsonUnit patch listener' + +configurations { + agent +} + +dependencies { + agent('org.aspectj:aspectjweaver') + + testCompile project(':allure-jsonunit') + testCompile project(':allure-junit-platform') + testCompile('com.github.tomakehurst:wiremock') + testCompile('org.junit.jupiter:junit-jupiter-api') + testCompile('org.slf4j:slf4j-simple') + testCompile 'org.hamcrest:hamcrest-library' + testRuntime('org.junit.jupiter:junit-jupiter-engine') +} + +test { + systemProperty 'org.slf4j.simpleLogger.defaultLogLevel', 'debug' + systemProperty 'allure.model.indentOutput', true + + useJUnitPlatform { + includeEngines 'junit-jupiter' + } + + doFirst { + jvmArgs "-javaagent:${configurations.agent.singleFile}" + } +} diff --git a/examples/jsonunit-patch-listener/src/test/java/io/qameta/allure/jsonunit/JsonPatchListenerTest.java b/examples/jsonunit-patch-listener/src/test/java/io/qameta/allure/jsonunit/JsonPatchListenerTest.java new file mode 100644 index 000000000..900987e9c --- /dev/null +++ b/examples/jsonunit-patch-listener/src/test/java/io/qameta/allure/jsonunit/JsonPatchListenerTest.java @@ -0,0 +1,141 @@ +package io.qameta.allure.jsonunit; + +import com.google.common.base.Charsets; +import org.apache.tika.io.IOUtils; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static io.qameta.allure.jsonunit.JsonPatchMatcher.jsonEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class JsonPatchListenerTest { + + @Test + void shouldSeeEmptyDiffNodes() { + assertThat("{}", jsonEquals("{}")); + } + + @Test + void shouldSeeAddedNode() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\": \"1\"}", jsonEquals("{}"))); + + } + + @Test + void shouldSeeRemovedNode() { + assertThrows(AssertionError.class, () -> assertThat("{}", jsonEquals("{\"test\": \"1\"}"))); + } + + @Test + void shouldSeeEmptyForCheckAnyNode() { + assertThat("{\"test\":\"1\"}", jsonEquals("{\"test\": \"${json-unit.ignore}\"}")); + } + + @Test + void shouldSeeEmptyForCheckAnyBooleanNode() { + assertThat("{\"test\": true}", jsonEquals("{\"test\": \"${json-unit.any-boolean}\"}")); + } + + @Test + void shouldSeeEmptyForCheckAnyNumberNode() { + assertThat("{\"test\": 11}", jsonEquals("{\"test\": \"${json-unit.any-number}\"}")); + } + + @Test + void shouldSeeEmptyForCheckAnyStringNode() { + assertThat("{\"test\": \"1\"}", jsonEquals("{\"test\": \"${json-unit.any-string}\"}")); + } + + + @Test + void shouldSeeChangedStringNode() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\": \"2\"}", + jsonEquals("{\"test\": \"1\"}"))); + } + + @Test + void shouldSeeChangedNumberNode() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\": 2 }", + jsonEquals("{\"test\": 1}"))); + + } + + @Test + void shouldSeeChangedBooleanNode() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\": false}", + jsonEquals("{\"test\": true}"))); + } + + @Test + void shouldSeeChangedStructureNode() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\": false}", + jsonEquals("{\"test\": \"1\"}"))); + } + + @Test + void shouldSeeChangedArrayNode() { + assertThrows(AssertionError.class, () -> assertThat("[1, 2]", jsonEquals("[1, 1]"))); + } + + @Test + void shouldSeeRemovedArrayNode() { + assertThrows(AssertionError.class, () -> assertThat("[1]", jsonEquals("[1, 2]"))); + } + + @Test + void shouldSeeAddedArrayNode() { + assertThrows(AssertionError.class, () -> assertThat("[1, 2]", jsonEquals("[1]"))); + } + + @Test + void shouldSeeObjectDiffNodes() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\": { \"test1\": \"2\"} }", + jsonEquals("{\"test\": { \"test1\": \"1\"}}"))); + } + + @Test + void shouldSeeNullNode() { + assertThat(null, jsonEquals(null)); + } + + @Test + void shouldWorkWhenIgnoringArrayOrder() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\":[[4,2],[1,2]]}", + jsonEquals("{\"test\": [[1,2],[2,3]]}"))); + } + + @Test + void shouldSeeActualSource() { + assertThrows(AssertionError.class, () -> assertThat("{}", jsonEquals("{\"test\": \"1\"}"))); + } + + @Test + void shouldSeeExpectedSource() { + assertThrows(AssertionError.class, () -> assertThat("{}", jsonEquals("{\"test\": \"1\"}"))); + } + + @Test + void shouldSeeArrayChangeToNode() { + assertThrows(AssertionError.class, () -> assertThat("{\"test\":\"1\"}", + jsonEquals("[[1,2],[2,3],[1,1]]"))); + } + + @Test + void shouldSeeChangeNodeToArray() { + assertThrows(AssertionError.class, () -> assertThat("[[1,2],[2,3],[1,1]]", + jsonEquals("{\"test\":\"1\"}"))); + } + + @Test + void shouldSeeDifference() throws IOException { + assertThrows(AssertionError.class, () -> assertThat(getResourceAsString("left.json"), jsonEquals(getResourceAsString("right.json")))); + } + + private String getResourceAsString(String path) throws IOException { + return IOUtils.toString(JsonPatchListenerTest.class.getClassLoader().getResourceAsStream(path), + Charsets.UTF_8.name()); + } + +} \ No newline at end of file diff --git a/examples/jsonunit-patch-listener/src/test/resources/allure.properties b/examples/jsonunit-patch-listener/src/test/resources/allure.properties new file mode 100644 index 000000000..cb77d0a3e --- /dev/null +++ b/examples/jsonunit-patch-listener/src/test/resources/allure.properties @@ -0,0 +1 @@ +allure.results.directory=build/allure-results \ No newline at end of file diff --git a/examples/jsonunit-patch-listener/src/test/resources/left.json b/examples/jsonunit-patch-listener/src/test/resources/left.json new file mode 100644 index 000000000..4b3f21a4f --- /dev/null +++ b/examples/jsonunit-patch-listener/src/test/resources/left.json @@ -0,0 +1,97 @@ +{ + "name": "South America", + "summary": "South America (Spanish: América del Sur, Sudamérica or \nSuramérica; Portuguese: América do Sul; Quechua and Aymara: \nUrin Awya Yala; Guarani: Ñembyamérika; Dutch: Zuid-Amerika; \nFrench: Amérique du Sud) is a continent situated in the \nWestern Hemisphere, mostly in the Southern Hemisphere, with \na relatively small portion in the Northern Hemisphere. \nThe continent is also considered a subcontinent of the \nAmericas.[2][3] It is bordered on the west by the Pacific \nOcean and on the north and east by the Atlantic Ocean; \nNorth America and the Caribbean Sea lie to the northwest. \nIt includes twelve countries: Argentina, Bolivia, Brasil, \nChile, Colombia, Ecuador, Guyana, Paraguay, Peru, Suriname, \nUruguay, and Venezuela. The South American nations that \nborder the Caribbean Sea—including Colombia, Venezuela, \nGuyana, Suriname, as well as French Guiana, which is an \noverseas region of France—are a.k.a. Caribbean South \nAmerica. South America has an area of 17,840,000 square \nkilometers (6,890,000 sq mi). Its population as of 2005 \nhas been estimated at more than 371,090,000. South America \nranks fourth in area (after Asia, Africa, and North America) \nand fifth in population (after Asia, Africa, Europe, and \nNorth America). The word America was coined in 1507 by \ncartographers Martin Waldseemüller and Matthias Ringmann, \nafter Amerigo Vespucci, who was the first European to \nsuggest that the lands newly discovered by Europeans were \nnot India, but a New World unknown to Europeans.", + "timezone": [ + -4, + -2 + ], + "demographics": { + "population": 385744896, + "largestCities": [ + "São Paulo", + "Buenos Aires", + "Rio de Janeiro", + "Lima", + "Bogotá" + ] + }, + "languages": [ + "spanish", + "portuguese", + "inglés", + "dutch", + "french", + "quechua", + "guaraní", + "aimara", + "mapudungun" + ], + "countries": [ + { + "name": "Argentina", + "capital": "Rawson", + "independence": "1816-07-08T20:00:00.000Z", + "unasur": true + }, + { + "name": "Bolivia", + "capital": "La Paz", + "independence": "1825-08-05T21:00:00.000Z", + "unasur": true + }, + { + "name": "Peru", + "capital": "Lima", + "independence": "1821-07-27T21:00:00.000Z", + "unasur": true + }, + { + "name": "Brazil", + "capital": "Brasilia", + "independence": "1822-09-06T21:00:00.000Z", + "unasur": true + }, + { + "name": "Chile", + "capital": "Santiago", + "independence": "1818-02-11T21:00:00.000Z", + "unasur": true + }, + { + "name": "Ecuador", + "capital": "Quito", + "independence": "1809-08-09T21:00:00.000Z", + "unasur": true + }, + { + "name": "Guyana", + "capital": "Georgetown", + "independence": "1966-05-25T21:00:00.000Z", + "unasur": true + }, + { + "name": "Paraguay", + "capital": "Asunción", + "independence": "1811-05-13T21:00:00.000Z", + "unasur": true + }, + { + "name": "Suriname", + "capital": "Paramaribo", + "independence": "1975-11-24T21:00:00.000Z", + "unasur": true + }, + { + "name": "Antártida", + "unasur": false + }, + { + "name": "Colombia", + "capital": "Bogotá", + "independence": "1810-07-19T21:00:00.000Z", + "unasur": true, + "population": 42888594 + } + ], + "spanishName": "Sudamérica" +} \ No newline at end of file diff --git a/examples/jsonunit-patch-listener/src/test/resources/right.json b/examples/jsonunit-patch-listener/src/test/resources/right.json new file mode 100644 index 000000000..df1a0b8ce --- /dev/null +++ b/examples/jsonunit-patch-listener/src/test/resources/right.json @@ -0,0 +1,104 @@ +{ + "name": "South America", + "summary": "South America (Spanish: América del Sur, Sudamérica or \nSuramérica; Portuguese: América do Sul; Quechua and Aymara: \nUrin Awya Yala; Guarani: Ñembyamérika; Dutch: Zuid-Amerika; \nFrench: Amérique du Sud) is a continent situated in the \nWestern Hemisphere, mostly in the Southern Hemisphere, with \na relatively small portion in the Northern Hemisphere. \nThe continent is also considered a subcontinent of the \nAmericas.[2][3] It is bordered on the west by the Pacific \nOcean and on the north and east by the Atlantic Ocean; \nNorth America and the Caribbean Sea lie to the northwest. \nIt includes twelve countries: Argentina, Bolivia, Brazil, \nChile, Colombia, Ecuador, Guyana, Paraguay, Peru, Suriname, \nUruguay, and Venezuela. The South American nations that \nborder the Caribbean Sea—including Colombia, Venezuela, \nGuyana, Suriname, as well as French Guiana, which is an \noverseas region of France—are also known as Caribbean South \nAmerica. South America has an area of 17,840,000 square \nkilometers (6,890,000 sq mi). Its population as of 2005 \nhas been estimated at more than 371,090,000. South America \nranks fourth in area (after Asia, Africa, and North America) \nand fifth in population (after Asia, Africa, Europe, and \nNorth America). The word America was coined in 1507 by \ncartographers Martin Waldseemüller and Matthias Ringmann, \nafter Amerigo Vespucci, who was the first European to \nsuggest that the lands newly discovered by Europeans were \nnot India, but a New World unknown to Europeans.", + "surface": 17840000, + "timezone": [ + -4, + -2 + ], + "demographics": { + "population": 385742554, + "largestCities": [ + "São Paulo", + "Buenos Aires", + "Rio de Janeiro", + "Lima", + "Bogotá" + ] + }, + "languages": [ + "spanish", + "portuguese", + "english", + "dutch", + "french", + "quechua", + "guaraní", + "aimara", + "mapudungun" + ], + "countries": [ + { + "name": "Argentina", + "capital": "Buenos Aires", + "independence": "1816-07-08T20:00:00.000Z", + "unasur": true + }, + { + "name": "Bolivia", + "capital": "La Paz", + "independence": "1825-08-05T21:00:00.000Z", + "unasur": true + }, + { + "name": "Brazil", + "capital": "Brasilia", + "independence": "1822-09-06T21:00:00.000Z", + "unasur": true + }, + { + "name": "Chile", + "capital": "Santiago", + "independence": "1818-02-11T21:00:00.000Z", + "unasur": true + }, + { + "name": "Colombia", + "capital": "Bogotá", + "independence": "1810-07-19T21:00:00.000Z", + "unasur": true + }, + { + "name": "Ecuador", + "capital": "Quito", + "independence": "1809-08-09T21:00:00.000Z", + "unasur": true + }, + { + "name": "Guyana", + "capital": "Georgetown", + "independence": "1966-05-25T21:00:00.000Z", + "unasur": true + }, + { + "name": "Paraguay", + "capital": "Asunción", + "independence": "1811-05-13T21:00:00.000Z", + "unasur": true + }, + { + "name": "Peru", + "capital": "Lima", + "independence": "1821-07-27T21:00:00.000Z", + "unasur": true + }, + { + "name": "Suriname", + "capital": "Paramaribo", + "independence": "1975-11-24T21:00:00.000Z", + "unasur": true + }, + { + "name": "Uruguay", + "capital": "Montevideo", + "independence": "1825-08-24T21:00:00.000Z", + "unasur": true + }, + { + "name": "Venezuela", + "capital": "Caracas", + "independence": "1811-07-04T21:00:00.000Z", + "unasur": true + } + ] +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index af663d6c3..29ce6d9a3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,6 +23,7 @@ include 'allure-spock' include 'allure-assertj' include 'allure-jbehave' include 'allure-selenide' +include 'allure-jsonunit' def examples = [ 'testng', @@ -32,7 +33,8 @@ def examples = [ 'http-client-attachment', 'rest-assured', 'okhttp3', - 'spock' + 'spock', + 'jsonunit-patch-listener' ] examples.forEach({