From 81b55d470bc179d78eedcf80708f42afa9b7463d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 19 Jul 2018 11:11:38 +0100 Subject: [PATCH] Refine missing field detection logic for paths with multiple arrays Previously, missing field detection worked correctly for paths containing a single array, but if the path contained multiple arrays the extracted value would be a list containing a single empty list. In this case the field would not be considered missing when, in fact it should have been. This commit updates the missing field detection logic to recursively examine the extracted value and, when it's a collection, the values that it contains. As a result, a field will be considered to be missing if it isn't present, if it's an empty collection, or if it's a collection that only contains empty collections or, to any depth, collections of empty collections. Closes gh-519 --- .../restdocs/payload/JsonContentHandler.java | 19 +++++++++++++-- .../payload/JsonContentHandlerTests.java | 23 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) 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 4187b514..a3c4d47d 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 @@ -86,8 +86,23 @@ class JsonContentHandler implements ContentHandler { } ExtractedField extracted = this.fieldProcessor.extract(candidate.getPath(), payload); - return extracted.getValue() instanceof Collection - && ((Collection) extracted.getValue()).isEmpty(); + return isEmptyCollection(extracted.getValue()); + } + + private boolean isEmptyCollection(Object value) { + if (!(value instanceof Collection)) { + return false; + } + Collection collection = (Collection) value; + if (collection.isEmpty()) { + return true; + } + for (Object entry : collection) { + if (!isEmptyCollection(entry)) { + return false; + } + } + return true; } @Override 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 ad1d4463..4040300a 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 @@ -158,7 +158,7 @@ public class JsonContentHandlerTests { } @Test - public void describedFieldThatIsSometimesPresentChildOfOptionalArrayIsNotConsideredMissing() { + public void describedSometimesPresentFieldThatIsChildOfSometimesPresentOptionalArrayIsNotConsideredMissing() { List missingFields = new JsonContentHandler( "{\"a\":[ {\"b\": \"bravo\"}, {\"b\": \"bravo\", \"c\": { \"d\": \"delta\"}}]}" .getBytes()).findMissingFields( @@ -167,4 +167,25 @@ public class JsonContentHandlerTests { assertThat(missingFields.size(), is(equalTo(0))); } + @Test + public void describedMissingFieldThatIsChildOfNestedOptionalArrayThatIsEmptyIsNotConsideredMissing() { + List missingFields = new JsonContentHandler( + "{\"a\":[{\"b\":[]}]}".getBytes()).findMissingFields( + Arrays.asList(new FieldDescriptor("a.[].b").optional(), + new FieldDescriptor("a.[].b.[]").optional(), + new FieldDescriptor("a.[].b.[].c"))); + assertThat(missingFields.size(), is(equalTo(0))); + } + + @Test + public void describedMissingFieldThatIsChildOfNestedOptionalArrayThatContainsAnObjectIsConsideredMissing() { + List missingFields = new JsonContentHandler( + "{\"a\":[{\"b\":[{}]}]}".getBytes()).findMissingFields( + Arrays.asList(new FieldDescriptor("a.[].b").optional(), + new FieldDescriptor("a.[].b.[]").optional(), + new FieldDescriptor("a.[].b.[].c"))); + assertThat(missingFields.size(), is(equalTo(1))); + assertThat(missingFields.get(0).getPath(), is(equalTo("a.[].b.[].c"))); + } + }