diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java index afacb6e1..86dbd7b4 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java @@ -52,8 +52,10 @@ class JsonContentHandler implements ContentHandler { List missingFields = new ArrayList<>(); Object payload = readContent(); for (FieldDescriptor fieldDescriptor : fieldDescriptors) { - if (!fieldDescriptor.isOptional() && !this.fieldProcessor - .hasField(fieldDescriptor.getPath(), payload)) { + if (!fieldDescriptor.isOptional() + && !this.fieldProcessor.hasField(fieldDescriptor.getPath(), payload) + && !isNestedBeneathMissingOptionalField(fieldDescriptor, + fieldDescriptors, payload)) { missingFields.add(fieldDescriptor); } } @@ -61,6 +63,20 @@ class JsonContentHandler implements ContentHandler { return missingFields; } + private boolean isNestedBeneathMissingOptionalField(FieldDescriptor missing, + List fieldDescriptors, Object payload) { + List candidates = new ArrayList<>(fieldDescriptors); + candidates.remove(missing); + for (FieldDescriptor candidate : candidates) { + if (candidate.isOptional() + && missing.getPath().startsWith(candidate.getPath()) + && !this.fieldProcessor.hasField(candidate.getPath(), payload)) { + return true; + } + } + return false; + } + @Override public String getUndocumentedContent(List fieldDescriptors) { Object content = readContent(); diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java index b2e5a582..e275bd92 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java @@ -17,6 +17,8 @@ package org.springframework.restdocs.payload; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import org.junit.Rule; import org.junit.Test; @@ -107,4 +109,42 @@ public class JsonContentHandlerTests { new JsonContentHandler("Non-JSON content".getBytes()); } + @Test + public void describedFieldThatIsNotPresentIsConsideredMissing() { + List missingFields = new JsonContentHandler( + "{\"a\": \"alpha\", \"b\":\"bravo\"}".getBytes()) + .findMissingFields(Arrays.asList(new FieldDescriptor("a"), + new FieldDescriptor("b"), new FieldDescriptor("c"))); + assertThat(missingFields.size(), is(equalTo(1))); + assertThat(missingFields.get(0).getPath(), is(equalTo("c"))); + } + + @Test + public void describedOptionalFieldThatIsNotPresentIsNotConsideredMissing() { + List missingFields = new JsonContentHandler( + "{\"a\": \"alpha\", \"b\":\"bravo\"}".getBytes()).findMissingFields( + Arrays.asList(new FieldDescriptor("a"), new FieldDescriptor("b"), + new FieldDescriptor("c").optional())); + assertThat(missingFields.size(), is(equalTo(0))); + } + + @Test + public void describedFieldThatIsNotPresentNestedBeneathOptionalFieldThatIsPresentIsConsideredMissing() { + List missingFields = new JsonContentHandler( + "{\"a\":\"alpha\",\"b\":\"bravo\"}".getBytes()).findMissingFields( + Arrays.asList(new FieldDescriptor("a").optional(), + new FieldDescriptor("b"), new FieldDescriptor("a.c"))); + assertThat(missingFields.size(), is(equalTo(1))); + assertThat(missingFields.get(0).getPath(), is(equalTo("a.c"))); + } + + @Test + public void describedFieldThatIsNotPresentNestedBeneathOptionalFieldThatIsNotPresentIsNotConsideredMissing() { + List missingFields = new JsonContentHandler( + "{\"b\":\"bravo\"}".getBytes()).findMissingFields( + Arrays.asList(new FieldDescriptor("a").optional(), + new FieldDescriptor("b"), new FieldDescriptor("a.c"))); + assertThat(missingFields.size(), is(equalTo(0))); + } + }