Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* extracted and removed.
*
* @author Andy Wilkinson
* @author Sharang Gupta
*
*/
final class JsonFieldProcessor {
Expand Down Expand Up @@ -72,6 +73,11 @@ public void foundMatch(Match match) {
match.remove();
}

@Override
public void foundEmptyCollection(Match match) {
match.remove();
}

});
}

Expand All @@ -83,6 +89,11 @@ public void foundMatch(Match match) {
match.removeSubsection();
}

@Override
public void foundEmptyCollection(Match match) {
match.removeSubsection();
}

});
}

Expand All @@ -107,6 +118,9 @@ private void handleCollectionPayload(Collection<?> collection, MatchCallback mat
if (context.isLeaf()) {
matchCallback.foundMatch(new LeafCollectionMatch(collection, context.getParentMatch()));
}
else if (collection.isEmpty()) {
matchCallback.foundEmptyCollection(new LeafCollectionMatch(collection, context.getParentMatch()));
}
else {
Iterator<?> items = collection.iterator();
while (items.hasNext()) {
Expand Down Expand Up @@ -369,6 +383,14 @@ private interface MatchCallback {
default void absent() {
}

/**
* Called when the path descends into a collection that has no entries. The
* collection is covered by the path but contains nothing that can be matched.
* @param match a match for the empty collection
*/
default void foundEmptyCollection(Match match) {
}

}

private interface Match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,13 @@ void describedMissingFieldThatIsChildOfOptionalObjectThatIsNullIsNotConsideredMi
assertThat(missingFields.size()).isEqualTo(0);
}

@Test
void describedFieldBeneathArrayThatIsSometimesEmptyDoesNotLeaveUndocumentedContent() {
List<FieldDescriptor> descriptors = Arrays.asList(new FieldDescriptor("count"),
new FieldDescriptor("items[].k1"), new FieldDescriptor("items[].k2[].name"));
String content = "{\"count\": 2, \"items\": [{\"k1\": \"v1\", \"k2\": []}, "
+ "{\"k1\": \"v2\", \"k2\": [{\"name\": \"joe\"}, {\"name\": \"alice\"}]}]}";
assertThat(new JsonContentHandler(content.getBytes(), descriptors).getUndocumentedContent()).isNull();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,32 @@ void removeSubsectionRemovesArrayWithListEntries() {
assertThat(payload.size()).isEqualTo(0);
}

@SuppressWarnings("unchecked")
@Test
void removeFieldBeneathArrayThatIsSometimesEmpty() {
Map<String, Object> payload = new ObjectMapper()
.readValue("{\"a\": [{\"b\": []}, {\"b\": [{\"c\": \"charlie\"}, {\"c\": \"charlie\"}]}]}", Map.class);
this.fieldProcessor.remove("a[].b[].c", payload);
assertThat(payload.size()).isEqualTo(0);
}

@SuppressWarnings("unchecked")
@Test
void removeFieldBeneathArrayThatIsAlwaysEmpty() {
Map<String, Object> payload = new ObjectMapper().readValue("{\"a\": [{\"b\": []}]}", Map.class);
this.fieldProcessor.remove("a[].b[].c", payload);
assertThat(payload.size()).isEqualTo(0);
}

@SuppressWarnings("unchecked")
@Test
void removeSubsectionBeneathArrayThatIsSometimesEmpty() {
Map<String, Object> payload = new ObjectMapper()
.readValue("{\"a\": [{\"b\": []}, {\"b\": [{\"c\": {\"d\": \"delta\"}}]}]}", Map.class);
this.fieldProcessor.removeSubsection("a[].b[].c", payload);
assertThat(payload.size()).isEqualTo(0);
}

@Test
void extractNestedEntryWithDotInKeys() {
Map<String, Object> payload = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,22 @@ void optionalFieldBeneathArrayThatIsSometimesAbsent(OperationBuilder operationBu
.row("`a[].c`", "`Number`", "two"));
}

@RenderedSnippetTest
void fieldBeneathArrayThatIsSometimesEmpty(OperationBuilder operationBuilder, AssertableSnippets snippets)
throws IOException {
new ResponseFieldsSnippet(
Arrays.asList(fieldWithPath("count").description("one"), fieldWithPath("items[].k1").description("two"),
fieldWithPath("items[].k2[].name").description("three")))
.document(operationBuilder.response()
.content("{\"count\": 2, \"items\": [{\"k1\": \"v1\", \"k2\": []}, "
+ "{\"k1\": \"v2\", \"k2\": [{\"name\": \"joe\"}, {\"name\": \"alice\"}]}]}")
.build());
assertThat(snippets.responseFields()).isTable((table) -> table.withHeader("Path", "Type", "Description")
.row("`count`", "`Number`", "one")
.row("`items[].k1`", "`String`", "two")
.row("`items[].k2[].name`", "`String`", "three"));
}

@RenderedSnippetTest
void typeDeterminationDoesNotSetTypeOnDescriptor(OperationBuilder operationBuilder, AssertableSnippets snippets)
throws IOException {
Expand Down