Improve testing of the generated documentation snippets
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* 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.springframework.restdocs;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown to indicate a problem with a RESTful resource's
|
||||
* documentation.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class RestDocumentationException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Creates a new {@code RestDocumentationException} described by the given
|
||||
* {@code message}
|
||||
* @param message the message that describes the documentation problem
|
||||
*/
|
||||
public RestDocumentationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -148,7 +148,10 @@ public abstract class HttpDocumentation {
|
||||
}
|
||||
}
|
||||
this.writer.println();
|
||||
this.writer.println(this.result.getResponse().getContentAsString());
|
||||
String content = this.result.getResponse().getContentAsString();
|
||||
if (StringUtils.hasText(content)) {
|
||||
this.writer.println(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.restdocs.hypermedia;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -26,6 +24,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationException;
|
||||
import org.springframework.restdocs.snippet.DocumentationWriter;
|
||||
import org.springframework.restdocs.snippet.DocumentationWriter.TableAction;
|
||||
import org.springframework.restdocs.snippet.DocumentationWriter.TableWriter;
|
||||
@@ -94,10 +93,13 @@ public class LinkSnippetResultHandler extends SnippetWritingResultHandler {
|
||||
+ undocumentedRels;
|
||||
}
|
||||
if (!missingRels.isEmpty()) {
|
||||
if (message.length() > 0) {
|
||||
message += ". ";
|
||||
}
|
||||
message += "Links with the following relations were not found in the response: "
|
||||
+ missingRels;
|
||||
}
|
||||
fail(message);
|
||||
throw new RestDocumentationException(message);
|
||||
}
|
||||
|
||||
Assert.isTrue(actualRels.equals(expectedRels));
|
||||
|
||||
@@ -121,7 +121,6 @@ class FieldProcessor {
|
||||
.getParentMatch()))) {
|
||||
return false;
|
||||
}
|
||||
;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
@@ -51,14 +53,17 @@ class FieldValidator {
|
||||
String message = "";
|
||||
if (!undocumentedPayload.isEmpty()) {
|
||||
message += String.format(
|
||||
"Portions of the payload were not documented:%n%s",
|
||||
"The following parts of the payload were not documented:%n%s",
|
||||
this.objectMapper.writeValueAsString(undocumentedPayload));
|
||||
}
|
||||
if (!missingFields.isEmpty()) {
|
||||
if (message.length() > 0) {
|
||||
message += String.format("%n");
|
||||
}
|
||||
message += "Fields with the following paths were not found in the payload: "
|
||||
+ missingFields;
|
||||
}
|
||||
throw new FieldValidationException(message);
|
||||
throw new RestDocumentationException(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,12 +91,4 @@ class FieldValidator {
|
||||
return payload;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class FieldValidationException extends RuntimeException {
|
||||
|
||||
FieldValidationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,23 +16,19 @@
|
||||
|
||||
package org.springframework.restdocs.curl;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.documentCurlRequest;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.codeBlock;
|
||||
import static org.springframework.restdocs.test.StubMvcResult.result;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.StubMvcResult;
|
||||
import org.springframework.restdocs.test.ExpectedSnippet;
|
||||
|
||||
/**
|
||||
* Tests for {@link CurlDocumentation}
|
||||
@@ -43,224 +39,174 @@ import org.springframework.restdocs.StubMvcResult;
|
||||
*/
|
||||
public class CurlDocumentationTests {
|
||||
|
||||
private final File outputDir = new File("build/curl-documentation-tests");
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
System.setProperty("org.springframework.restdocs.outputDir",
|
||||
this.outputDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
@Rule
|
||||
public ExpectedSnippet snippet = new ExpectedSnippet();
|
||||
|
||||
@Test
|
||||
public void getRequest() throws IOException {
|
||||
documentCurlRequest("get-request").handle(
|
||||
new StubMvcResult(new MockHttpServletRequest("GET", "/foo"), null));
|
||||
assertThat(requestSnippetLines("get-request"),
|
||||
hasItem("$ curl 'http://localhost/foo' -i"));
|
||||
this.snippet.expectCurlRequest("get-request").withContents(
|
||||
codeBlock("bash").content("$ curl 'http://localhost/foo' -i"));
|
||||
documentCurlRequest("get-request").handle(result(get("/foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonGetRequest() throws IOException {
|
||||
documentCurlRequest("non-get-request").handle(
|
||||
new StubMvcResult(new MockHttpServletRequest("POST", "/foo"), null));
|
||||
assertThat(requestSnippetLines("non-get-request"),
|
||||
hasItem("$ curl 'http://localhost/foo' -i -X POST"));
|
||||
this.snippet.expectCurlRequest("non-get-request").withContents(
|
||||
codeBlock("bash").content("$ curl 'http://localhost/foo' -i -X POST"));
|
||||
documentCurlRequest("non-get-request").handle(result(post("/foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithContent() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setContent("content".getBytes());
|
||||
this.snippet.expectCurlRequest("request-with-content").withContents(
|
||||
codeBlock("bash")
|
||||
.content("$ curl 'http://localhost/foo' -i -d 'content'"));
|
||||
documentCurlRequest("request-with-content").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-content"),
|
||||
hasItem("$ curl 'http://localhost/foo' -i -d 'content'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWitUriQueryString() throws IOException {
|
||||
documentCurlRequest("request-with-uri-query-string").handle(
|
||||
new StubMvcResult(new MockHttpServletRequest("GET", "/foo?param=value"),
|
||||
null));
|
||||
assertThat(requestSnippetLines("request-with-uri-query-string"),
|
||||
hasItem("$ curl 'http://localhost/foo?param=value' -i"));
|
||||
result(get("/foo").content("content")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithQueryString() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setQueryString("param=value");
|
||||
this.snippet.expectCurlRequest("request-with-query-string")
|
||||
.withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://localhost/foo?param=value' -i"));
|
||||
documentCurlRequest("request-with-query-string").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-query-string"),
|
||||
hasItem("$ curl 'http://localhost/foo?param=value' -i"));
|
||||
result(get("/foo?param=value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithOneParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addParameter("k1", "v1");
|
||||
this.snippet.expectCurlRequest("request-with-one-parameter").withContents(
|
||||
codeBlock("bash").content("$ curl 'http://localhost/foo?k1=v1' -i"));
|
||||
documentCurlRequest("request-with-one-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-one-parameter"),
|
||||
hasItem("$ curl 'http://localhost/foo?k1=v1' -i"));
|
||||
result(get("/foo").param("k1", "v1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithMultipleParameters() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addParameter("k1", "v1");
|
||||
request.addParameter("k2", "v2");
|
||||
request.addParameter("k1", "v1-bis");
|
||||
this.snippet.expectCurlRequest("request-with-multiple-parameters").withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://localhost/foo?k1=v1&k1=v1-bis&k2=v2' -i"));
|
||||
documentCurlRequest("request-with-multiple-parameters").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-multiple-parameters"),
|
||||
hasItem("$ curl 'http://localhost/foo?k1=v1&k1=v1-bis&k2=v2' -i"));
|
||||
result(get("/foo").param("k1", "v1").param("k2", "v2")
|
||||
.param("k1", "v1-bis")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithUrlEncodedParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addParameter("k1", "foo bar&");
|
||||
this.snippet.expectCurlRequest("request-with-url-encoded-parameter")
|
||||
.withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://localhost/foo?k1=foo+bar%26' -i"));
|
||||
documentCurlRequest("request-with-url-encoded-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-url-encoded-parameter"),
|
||||
hasItem("$ curl 'http://localhost/foo?k1=foo+bar%26' -i"));
|
||||
result(get("/foo").param("k1", "foo bar&")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithOneParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
request.addParameter("k1", "v1");
|
||||
this.snippet.expectCurlRequest("post-request-with-one-parameter").withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://localhost/foo' -i -X POST -d 'k1=v1'"));
|
||||
documentCurlRequest("post-request-with-one-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("post-request-with-one-parameter"),
|
||||
hasItem("$ curl 'http://localhost/foo' -i -X POST -d 'k1=v1'"));
|
||||
result(post("/foo").param("k1", "v1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithMultipleParameters() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
request.addParameter("k1", "v1");
|
||||
request.addParameter("k2", "v2");
|
||||
request.addParameter("k1", "v1-bis");
|
||||
this.snippet.expectCurlRequest("post-request-with-multiple-parameters")
|
||||
.withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://localhost/foo' -i -X POST"
|
||||
+ " -d 'k1=v1&k1=v1-bis&k2=v2'"));
|
||||
documentCurlRequest("post-request-with-multiple-parameters").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(
|
||||
requestSnippetLines("post-request-with-multiple-parameters"),
|
||||
hasItem("$ curl 'http://localhost/foo' -i -X POST -d 'k1=v1&k1=v1-bis&k2=v2'"));
|
||||
result(post("/foo").param("k1", "v1", "v1-bis").param("k2", "v2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithUrlEncodedParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
request.addParameter("k1", "a&b");
|
||||
this.snippet
|
||||
.expectCurlRequest("post-request-with-url-encoded-parameter")
|
||||
.withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://localhost/foo' -i -X POST -d 'k1=a%26b'"));
|
||||
documentCurlRequest("post-request-with-url-encoded-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("post-request-with-url-encoded-parameter"),
|
||||
hasItem("$ curl 'http://localhost/foo' -i -X POST -d 'k1=a%26b'"));
|
||||
result(post("/foo").param("k1", "a&b")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithHeaders() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
request.addHeader("a", "alpha");
|
||||
this.snippet.expectCurlRequest("request-with-headers").withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://localhost/foo' -i"
|
||||
+ " -H 'Content-Type: application/json' -H 'a: alpha'"));
|
||||
documentCurlRequest("request-with-headers").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(
|
||||
requestSnippetLines("request-with-headers"),
|
||||
hasItem("$ curl 'http://localhost/foo' -i -H 'Content-Type: application/json' -H 'a: alpha'"));
|
||||
result(get("/foo").contentType(MediaType.APPLICATION_JSON).header("a",
|
||||
"alpha")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpWithNonStandardPort() throws IOException {
|
||||
this.snippet.expectCurlRequest("http-with-non-standard-port").withContents(
|
||||
codeBlock("bash").content("$ curl 'http://localhost:8080/foo' -i"));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setServerPort(8080);
|
||||
documentCurlRequest("http-with-non-standard-port").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("http-with-non-standard-port"),
|
||||
hasItem("$ curl 'http://localhost:8080/foo' -i"));
|
||||
documentCurlRequest("http-with-non-standard-port").handle(result(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsWithStandardPort() throws IOException {
|
||||
this.snippet.expectCurlRequest("https-with-standard-port").withContents(
|
||||
codeBlock("bash").content("$ curl 'https://localhost/foo' -i"));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setServerPort(443);
|
||||
request.setScheme("https");
|
||||
documentCurlRequest("https-with-standard-port").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("https-with-standard-port"),
|
||||
hasItem("$ curl 'https://localhost/foo' -i"));
|
||||
documentCurlRequest("https-with-standard-port").handle(result(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsWithNonStandardPort() throws IOException {
|
||||
this.snippet.expectCurlRequest("https-with-non-standard-port").withContents(
|
||||
codeBlock("bash").content("$ curl 'https://localhost:8443/foo' -i"));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setServerPort(8443);
|
||||
request.setScheme("https");
|
||||
documentCurlRequest("https-with-non-standard-port").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("https-with-non-standard-port"),
|
||||
hasItem("$ curl 'https://localhost:8443/foo' -i"));
|
||||
documentCurlRequest("https-with-non-standard-port").handle(result(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithCustomHost() throws IOException {
|
||||
this.snippet.expectCurlRequest("request-with-custom-host").withContents(
|
||||
codeBlock("bash").content("$ curl 'http://api.example.com/foo' -i"));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setServerName("api.example.com");
|
||||
documentCurlRequest("request-with-custom-host").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-custom-host"),
|
||||
hasItem("$ curl 'http://api.example.com/foo' -i"));
|
||||
documentCurlRequest("request-with-custom-host").handle(result(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithContextPathWithSlash() throws IOException {
|
||||
this.snippet.expectCurlRequest("request-with-custom-context-with-slash")
|
||||
.withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://api.example.com/v3/foo' -i"));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setServerName("api.example.com");
|
||||
request.setContextPath("/v3");
|
||||
documentCurlRequest("request-with-custom-context-with-slash").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-custom-context-with-slash"),
|
||||
hasItem("$ curl 'http://api.example.com/v3/foo' -i"));
|
||||
result(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithContextPathWithoutSlash() throws IOException {
|
||||
this.snippet.expectCurlRequest("request-with-custom-context-without-slash")
|
||||
.withContents(
|
||||
codeBlock("bash").content(
|
||||
"$ curl 'http://api.example.com/v3/foo' -i"));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setServerName("api.example.com");
|
||||
request.setContextPath("v3");
|
||||
documentCurlRequest("request-with-custom-context-without-slash").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("request-with-custom-context-without-slash"),
|
||||
hasItem("$ curl 'http://api.example.com/v3/foo' -i"));
|
||||
result(request));
|
||||
}
|
||||
|
||||
private List<String> requestSnippetLines(String snippetName) throws IOException {
|
||||
return snippetLines(snippetName, "curl-request");
|
||||
}
|
||||
|
||||
private List<String> snippetLines(String snippetName, String snippetType)
|
||||
throws IOException {
|
||||
File snippetDir = new File(this.outputDir, snippetName);
|
||||
File snippetFile = new File(snippetDir, snippetType + ".adoc");
|
||||
String line = null;
|
||||
List<String> lines = new ArrayList<String>();
|
||||
BufferedReader reader = new BufferedReader(new FileReader(snippetFile));
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.close();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,27 +16,25 @@
|
||||
|
||||
package org.springframework.restdocs.http;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
import static org.springframework.restdocs.http.HttpDocumentation.documentHttpRequest;
|
||||
import static org.springframework.restdocs.http.HttpDocumentation.documentHttpResponse;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.httpRequest;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.httpResponse;
|
||||
import static org.springframework.restdocs.test.StubMvcResult.result;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.restdocs.StubMvcResult;
|
||||
import org.springframework.restdocs.test.ExpectedSnippet;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpDocumentation}
|
||||
@@ -45,131 +43,93 @@ import org.springframework.restdocs.StubMvcResult;
|
||||
*/
|
||||
public class HttpDocumentationTests {
|
||||
|
||||
private final File outputDir = new File("build/http-documentation-tests");
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
System.setProperty("org.springframework.restdocs.outputDir",
|
||||
this.outputDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
@Rule
|
||||
public final ExpectedSnippet snippet = new ExpectedSnippet();
|
||||
|
||||
@Test
|
||||
public void getRequest() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addHeader("Alpha", "a");
|
||||
documentHttpRequest("get-request").handle(new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("get-request"),
|
||||
hasItems("GET /foo HTTP/1.1", "Alpha: a"));
|
||||
this.snippet.expectHttpRequest("get-request").withContents(
|
||||
httpRequest(GET, "/foo").header("Alpha", "a"));
|
||||
|
||||
documentHttpRequest("get-request").handle(
|
||||
result(get("/foo").header("Alpha", "a")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestWithQueryString() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo?bar=baz");
|
||||
this.snippet.expectHttpRequest("get-request-with-query-string").withContents(
|
||||
httpRequest(GET, "/foo?bar=baz"));
|
||||
|
||||
documentHttpRequest("get-request-with-query-string").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("get-request-with-query-string"),
|
||||
hasItems("GET /foo?bar=baz HTTP/1.1"));
|
||||
result(get("/foo?bar=baz")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestWithParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addParameter("b&r", "baz");
|
||||
this.snippet.expectHttpRequest("get-request-with-parameter").withContents(
|
||||
httpRequest(GET, "/foo?b%26r=baz"));
|
||||
|
||||
documentHttpRequest("get-request-with-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("get-request-with-parameter"),
|
||||
hasItems("GET /foo?b%26r=baz HTTP/1.1"));
|
||||
result(get("/foo").param("b&r", "baz")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithContent() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
byte[] content = "Hello, world".getBytes();
|
||||
request.setContent(content);
|
||||
this.snippet.expectHttpRequest("post-request-with-content").withContents(
|
||||
httpRequest(POST, "/foo") //
|
||||
.content("Hello, world"));
|
||||
|
||||
documentHttpRequest("post-request-with-content").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("post-request-with-content"),
|
||||
hasItems("POST /foo HTTP/1.1", "Hello, world"));
|
||||
result(post("/foo").content("Hello, world")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
request.addParameter("b&r", "baz");
|
||||
request.addParameter("a", "alpha");
|
||||
this.snippet.expectHttpRequest("post-request-with-parameter").withContents(
|
||||
httpRequest(POST, "/foo") //
|
||||
.header("Content-Type", "application/x-www-form-urlencoded") //
|
||||
.content("b%26r=baz&a=alpha"));
|
||||
|
||||
documentHttpRequest("post-request-with-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(
|
||||
requestSnippetLines("post-request-with-parameter"),
|
||||
hasItems("POST /foo HTTP/1.1",
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
"b%26r=baz&a=alpha"));
|
||||
result(post("/foo").param("b&r", "baz").param("a", "alpha")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicResponse() throws IOException {
|
||||
documentHttpResponse("basic-response").handle(
|
||||
new StubMvcResult(null, new MockHttpServletResponse()));
|
||||
assertThat(responseSnippetLines("basic-response"), hasItem("HTTP/1.1 200 OK"));
|
||||
this.snippet.expectHttpResponse("basic-response").withContents(httpResponse(OK));
|
||||
documentHttpResponse("basic-response").handle(result());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonOkResponse() throws IOException {
|
||||
this.snippet.expectHttpResponse("non-ok-response").withContents(
|
||||
httpResponse(BAD_REQUEST));
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
documentHttpResponse("non-ok-response").handle(new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("non-ok-response"),
|
||||
hasItem("HTTP/1.1 400 Bad Request"));
|
||||
response.setStatus(BAD_REQUEST.value());
|
||||
documentHttpResponse("non-ok-response").handle(result(response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithHeaders() throws IOException {
|
||||
this.snippet.expectHttpResponse("response-with-headers").withContents(
|
||||
httpResponse(OK) //
|
||||
.header("Content-Type", "application/json") //
|
||||
.header("a", "alpha"));
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.setHeader("a", "alpha");
|
||||
documentHttpResponse("non-ok-response").handle(new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("non-ok-response"),
|
||||
hasItems("HTTP/1.1 200 OK", "Content-Type: application/json", "a: alpha"));
|
||||
documentHttpResponse("response-with-headers").handle(result(response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithContent() throws IOException {
|
||||
this.snippet.expectHttpResponse("response-with-content").withContents(
|
||||
httpResponse(OK).content("content"));
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().append("content");
|
||||
documentHttpResponse("response-with-content").handle(
|
||||
new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("response-with-content"),
|
||||
hasItems("HTTP/1.1 200 OK", "content"));
|
||||
documentHttpResponse("response-with-content").handle(result(response));
|
||||
}
|
||||
|
||||
private List<String> requestSnippetLines(String snippetName) throws IOException {
|
||||
return snippetLines(snippetName, "http-request");
|
||||
}
|
||||
|
||||
private List<String> responseSnippetLines(String snippetName) throws IOException {
|
||||
return snippetLines(snippetName, "http-response");
|
||||
}
|
||||
|
||||
private List<String> snippetLines(String snippetName, String snippetType)
|
||||
throws IOException {
|
||||
File snippetDir = new File(this.outputDir, snippetName);
|
||||
File snippetFile = new File(snippetDir, snippetType + ".adoc");
|
||||
String line = null;
|
||||
List<String> lines = new ArrayList<String>();
|
||||
BufferedReader reader = new BufferedReader(new FileReader(snippetFile));
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.close();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* 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.springframework.restdocs.hypermedia;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.documentLinks;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.tableWithHeader;
|
||||
import static org.springframework.restdocs.test.StubMvcResult.result;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.restdocs.RestDocumentationException;
|
||||
import org.springframework.restdocs.test.ExpectedSnippet;
|
||||
|
||||
/**
|
||||
* Tests for {@link HypermediaDocumentation}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class HypermediaDocumentationTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedSnippet snippet = new ExpectedSnippet();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void undocumentedLink() throws IOException {
|
||||
this.thrown.expect(RestDocumentationException.class);
|
||||
this.thrown.expectMessage(equalTo("Links with the following relations were not"
|
||||
+ " documented: [foo]"));
|
||||
documentLinks("undocumented-link",
|
||||
new StubLinkExtractor().withLinks(new Link("foo", "bar"))).handle(
|
||||
result());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingLink() throws IOException {
|
||||
this.thrown.expect(RestDocumentationException.class);
|
||||
this.thrown.expectMessage(equalTo("Links with the following relations were not"
|
||||
+ " found in the response: [foo]"));
|
||||
documentLinks("undocumented-link", new StubLinkExtractor(),
|
||||
new LinkDescriptor("foo").description("bar")).handle(result());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedLinkAndMissingLink() throws IOException {
|
||||
this.thrown.expect(RestDocumentationException.class);
|
||||
this.thrown.expectMessage(equalTo("Links with the following relations were not"
|
||||
+ " documented: [a]. Links with the following relations were not"
|
||||
+ " found in the response: [foo]"));
|
||||
documentLinks("undocumented-link-and-missing-link",
|
||||
new StubLinkExtractor().withLinks(new Link("a", "alpha")),
|
||||
new LinkDescriptor("foo").description("bar")).handle(result());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void documentedLinks() throws IOException {
|
||||
this.snippet.expectLinks("documented-links").withContents( //
|
||||
tableWithHeader("Relation", "Description") //
|
||||
.row("a", "one") //
|
||||
.row("b", "two"));
|
||||
documentLinks(
|
||||
"documented-links",
|
||||
new StubLinkExtractor().withLinks(new Link("a", "alpha"), new Link("b",
|
||||
"bravo")), new LinkDescriptor("a").description("one"),
|
||||
new LinkDescriptor("b").description("two")).handle(result());
|
||||
}
|
||||
|
||||
private static class StubLinkExtractor implements LinkExtractor {
|
||||
|
||||
private Map<String, List<Link>> linksByRel = new HashMap<String, List<Link>>();
|
||||
|
||||
@Override
|
||||
public Map<String, List<Link>> extractLinks(MockHttpServletResponse response)
|
||||
throws IOException {
|
||||
return this.linksByRel;
|
||||
}
|
||||
|
||||
private StubLinkExtractor withLinks(Link... links) {
|
||||
for (Link link : links) {
|
||||
List<Link> linksWithRel = this.linksByRel.get(link.getRel());
|
||||
if (linksWithRel == null) {
|
||||
linksWithRel = new ArrayList<Link>();
|
||||
this.linksByRel.put(link.getRel(), linksWithRel);
|
||||
}
|
||||
linksWithRel.add(link);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import java.util.Arrays;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.restdocs.payload.FieldValidator.FieldValidationException;
|
||||
import org.springframework.restdocs.RestDocumentationException;
|
||||
|
||||
/**
|
||||
* Tests for {@link FieldValidator}
|
||||
@@ -70,9 +70,10 @@ public class FieldValidatorTests {
|
||||
|
||||
@Test
|
||||
public void missingField() throws IOException {
|
||||
this.thrownException.expect(FieldValidationException.class);
|
||||
this.thrownException.expect(RestDocumentationException.class);
|
||||
this.thrownException
|
||||
.expectMessage(equalTo("Fields with the following paths were not found in the payload: [y, z]"));
|
||||
.expectMessage(equalTo("Fields with the following paths were not found"
|
||||
+ " in the payload: [y, z]"));
|
||||
this.fieldValidator.validate(this.payload, Arrays.asList(
|
||||
new FieldDescriptor("a"), new FieldDescriptor("a.b"),
|
||||
new FieldDescriptor("y"), new FieldDescriptor("z")));
|
||||
@@ -80,10 +81,10 @@ public class FieldValidatorTests {
|
||||
|
||||
@Test
|
||||
public void undocumentedField() throws IOException {
|
||||
this.thrownException.expect(FieldValidationException.class);
|
||||
this.thrownException
|
||||
.expectMessage(equalTo(String
|
||||
.format("Portions of the payload were not documented:%n{%n \"a\" : {%n \"c\" : true%n }%n}")));
|
||||
this.thrownException.expect(RestDocumentationException.class);
|
||||
this.thrownException.expectMessage(equalTo(String
|
||||
.format("The following parts of the payload were not"
|
||||
+ " documented:%n{%n \"a\" : {%n \"c\" : true%n }%n}")));
|
||||
this.fieldValidator.validate(this.payload,
|
||||
Arrays.asList(new FieldDescriptor("a.b"), new FieldDescriptor("a.d")));
|
||||
}
|
||||
|
||||
@@ -15,31 +15,24 @@
|
||||
*/
|
||||
package org.springframework.restdocs.payload;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.documentRequestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.documentResponseFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.tableWithHeader;
|
||||
import static org.springframework.restdocs.test.StubMvcResult.result;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.collection.IsIterableContainingInAnyOrder;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.restdocs.StubMvcResult;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.restdocs.RestDocumentationException;
|
||||
import org.springframework.restdocs.test.ExpectedSnippet;
|
||||
|
||||
/**
|
||||
* Tests for {@link PayloadDocumentation}
|
||||
@@ -48,40 +41,42 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class PayloadDocumentationTests {
|
||||
|
||||
private final File outputDir = new File("build/payload-documentation-tests");
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
System.setProperty("org.springframework.restdocs.outputDir",
|
||||
this.outputDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
@Rule
|
||||
public final ExpectedSnippet snippet = new ExpectedSnippet();
|
||||
|
||||
@Test
|
||||
public void requestWithFields() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setContent("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}".getBytes());
|
||||
this.snippet.expectRequestFields("request-with-fields").withContents( //
|
||||
tableWithHeader("Path", "Type", "Description") //
|
||||
.row("a.b", "Number", "one") //
|
||||
.row("a.c", "String", "two") //
|
||||
.row("a", "Object", "three"));
|
||||
|
||||
documentRequestFields("request-with-fields",
|
||||
fieldWithPath("a.b").description("one"),
|
||||
fieldWithPath("a.c").description("two"),
|
||||
fieldWithPath("a").description("three")).handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(
|
||||
snippet("request-with-fields", "request-fields"),
|
||||
is(asciidoctorTableWith(header("Path", "Type", "Description"),
|
||||
row("a.b", "Number", "one"), row("a.c", "String", "two"),
|
||||
row("a", "Object", "three"))));
|
||||
result(get("/foo").content("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithFields() throws IOException {
|
||||
this.snippet.expectResponseFields("response-with-fields").withContents(//
|
||||
tableWithHeader("Path", "Type", "Description") //
|
||||
.row("id", "Number", "one") //
|
||||
.row("date", "String", "two") //
|
||||
.row("assets", "Array", "three") //
|
||||
.row("assets[]", "Object", "four") //
|
||||
.row("assets[].id", "Number", "five") //
|
||||
.row("assets[].name", "String", "six"));
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter()
|
||||
.append("{\"id\": 67,\"date\": \"2015-01-20\",\"assets\": [{\"id\":356,\"name\": \"sample\"}]}");
|
||||
response.getWriter().append(
|
||||
"{\"id\": 67,\"date\": \"2015-01-20\",\"assets\":"
|
||||
+ " [{\"id\":356,\"name\": \"sample\"}]}");
|
||||
documentResponseFields("response-with-fields",
|
||||
fieldWithPath("id").description("one"),
|
||||
fieldWithPath("date").description("two"),
|
||||
@@ -89,67 +84,41 @@ public class PayloadDocumentationTests {
|
||||
fieldWithPath("assets[]").description("four"),
|
||||
fieldWithPath("assets[].id").description("five"),
|
||||
fieldWithPath("assets[].name").description("six")).handle(
|
||||
new StubMvcResult(new MockHttpServletRequest("GET", "/"), response));
|
||||
assertThat(
|
||||
snippet("response-with-fields", "response-fields"),
|
||||
is(asciidoctorTableWith(header("Path", "Type", "Description"),
|
||||
row("id", "Number", "one"), row("date", "String", "two"),
|
||||
row("assets", "Array", "three"),
|
||||
row("assets[]", "Object", "four"),
|
||||
row("assets[].id", "Number", "five"),
|
||||
row("assets[].name", "String", "six"))));
|
||||
result(response));
|
||||
}
|
||||
|
||||
private Matcher<Iterable<? extends String>> asciidoctorTableWith(String[] header,
|
||||
String[]... rows) {
|
||||
Collection<Matcher<? super String>> matchers = new ArrayList<Matcher<? super String>>();
|
||||
for (String headerItem : header) {
|
||||
matchers.add(equalTo(headerItem));
|
||||
}
|
||||
|
||||
for (String[] row : rows) {
|
||||
for (String rowItem : row) {
|
||||
matchers.add(equalTo(rowItem));
|
||||
}
|
||||
}
|
||||
|
||||
matchers.add(equalTo("|==="));
|
||||
matchers.add(equalTo(""));
|
||||
|
||||
return new IsIterableContainingInAnyOrder<String>(matchers);
|
||||
@Test
|
||||
public void undocumentedRequestField() throws IOException {
|
||||
this.thrown.expect(RestDocumentationException.class);
|
||||
this.thrown
|
||||
.expectMessage(startsWith("The following parts of the payload were not"
|
||||
+ " documented:"));
|
||||
documentRequestFields("undocumented-request-fields").handle(
|
||||
result(get("/foo").content("{\"a\": 5}")));
|
||||
}
|
||||
|
||||
private String[] header(String... columns) {
|
||||
String header = "|"
|
||||
+ StringUtils.collectionToDelimitedString(Arrays.asList(columns), "|");
|
||||
return new String[] { "", "|===", header, "" };
|
||||
@Test
|
||||
public void missingRequestField() throws IOException {
|
||||
this.thrown.expect(RestDocumentationException.class);
|
||||
this.thrown
|
||||
.expectMessage(equalTo("Fields with the following paths were not found"
|
||||
+ " in the payload: [a.b]"));
|
||||
documentRequestFields("missing-request-fields",
|
||||
fieldWithPath("a.b").description("one")).handle(
|
||||
result(get("/foo").content("{}")));
|
||||
}
|
||||
|
||||
private String[] row(String... entries) {
|
||||
List<String> lines = new ArrayList<String>();
|
||||
for (String entry : entries) {
|
||||
lines.add("|" + entry);
|
||||
}
|
||||
lines.add("");
|
||||
return lines.toArray(new String[lines.size()]);
|
||||
@Test
|
||||
public void undocumentedRequestFieldAndMissingRequestField() throws IOException {
|
||||
this.thrown.expect(RestDocumentationException.class);
|
||||
this.thrown
|
||||
.expectMessage(startsWith("The following parts of the payload were not"
|
||||
+ " documented:"));
|
||||
this.thrown
|
||||
.expectMessage(endsWith("Fields with the following paths were not found"
|
||||
+ " in the payload: [a.b]"));
|
||||
documentRequestFields("undocumented-request-field-and-missing-request-field",
|
||||
fieldWithPath("a.b").description("one")).handle(
|
||||
result(get("/foo").content("{ \"a\": { \"c\": 5 }}")));
|
||||
}
|
||||
|
||||
private List<String> snippet(String snippetName, String snippetType)
|
||||
throws IOException {
|
||||
File snippetDir = new File(this.outputDir, snippetName);
|
||||
File snippetFile = new File(snippetDir, snippetType + ".adoc");
|
||||
String line = null;
|
||||
List<String> lines = new ArrayList<String>();
|
||||
BufferedReader reader = new BufferedReader(new FileReader(snippetFile));
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.close();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* 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.springframework.restdocs.test;
|
||||
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.collection.IsIterableContainingInAnyOrder;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.restdocs.snippet.SnippetWritingResultHandler;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@code ExpectedSnippet} rule is used to verify that a
|
||||
* {@link SnippetWritingResultHandler} has generated the expected snippet.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ExpectedSnippet implements TestRule {
|
||||
|
||||
private String expectedName;
|
||||
|
||||
private String expectedType;
|
||||
|
||||
private Matcher<String> expectedContents;
|
||||
|
||||
private File outputDir;
|
||||
|
||||
@Override
|
||||
public Statement apply(final Statement base, Description description) {
|
||||
this.outputDir = new File("build/" + description.getTestClass().getSimpleName());
|
||||
return new OutputDirectoryStatement(new ExpectedSnippetStatement(base),
|
||||
this.outputDir);
|
||||
}
|
||||
|
||||
private static final class OutputDirectoryStatement extends Statement {
|
||||
|
||||
private final Statement delegate;
|
||||
|
||||
private final File outputDir;
|
||||
|
||||
public OutputDirectoryStatement(Statement delegate, File outputDir) {
|
||||
this.delegate = delegate;
|
||||
this.outputDir = outputDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
System.setProperty("org.springframework.restdocs.outputDir",
|
||||
this.outputDir.getAbsolutePath());
|
||||
try {
|
||||
this.delegate.evaluate();
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class ExpectedSnippetStatement extends Statement {
|
||||
|
||||
private final Statement delegate;
|
||||
|
||||
public ExpectedSnippetStatement(Statement delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
this.delegate.evaluate();
|
||||
verifySnippet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void verifySnippet() throws IOException {
|
||||
if (this.outputDir != null && this.expectedName != null) {
|
||||
File snippetDir = new File(this.outputDir, this.expectedName);
|
||||
File snippetFile = new File(snippetDir, this.expectedType + ".adoc");
|
||||
assertTrue("The file " + snippetFile + " does not exist or is not a file",
|
||||
snippetFile.isFile());
|
||||
if (this.expectedContents != null) {
|
||||
assertThat(read(snippetFile), this.expectedContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ExpectedSnippet expectCurlRequest(String name) {
|
||||
expect(name, "curl-request");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExpectedSnippet expectRequestFields(String name) {
|
||||
expect(name, "request-fields");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExpectedSnippet expectResponseFields(String name) {
|
||||
expect(name, "response-fields");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExpectedSnippet expectLinks(String name) {
|
||||
expect(name, "links");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExpectedSnippet expectHttpRequest(String name) {
|
||||
expect(name, "http-request");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExpectedSnippet expectHttpResponse(String name) {
|
||||
expect(name, "http-response");
|
||||
return this;
|
||||
}
|
||||
|
||||
private ExpectedSnippet expect(String name, String type) {
|
||||
this.expectedName = name;
|
||||
this.expectedType = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void withContents(Matcher<String> matcher) {
|
||||
this.expectedContents = matcher;
|
||||
}
|
||||
|
||||
private String read(File snippetFile) throws IOException {
|
||||
return FileCopyUtils.copyToString(new FileReader(snippetFile));
|
||||
}
|
||||
|
||||
public Matcher<Iterable<? extends String>> asciidoctorTableWith(String[] header,
|
||||
String[]... rows) {
|
||||
Collection<Matcher<? super String>> matchers = new ArrayList<Matcher<? super String>>();
|
||||
for (String headerItem : header) {
|
||||
matchers.add(equalTo(headerItem));
|
||||
}
|
||||
|
||||
for (String[] row : rows) {
|
||||
for (String rowItem : row) {
|
||||
matchers.add(equalTo(rowItem));
|
||||
}
|
||||
}
|
||||
|
||||
matchers.add(equalTo("|==="));
|
||||
matchers.add(equalTo(""));
|
||||
|
||||
return new IsIterableContainingInAnyOrder<String>(matchers);
|
||||
}
|
||||
|
||||
public String[] header(String... columns) {
|
||||
String header = "|"
|
||||
+ StringUtils.collectionToDelimitedString(Arrays.asList(columns), "|");
|
||||
return new String[] { "", "|===", header, "" };
|
||||
}
|
||||
|
||||
public String[] row(String... entries) {
|
||||
List<String> lines = new ArrayList<String>();
|
||||
for (String entry : entries) {
|
||||
lines.add("|" + entry);
|
||||
}
|
||||
lines.add("");
|
||||
return lines.toArray(new String[lines.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* 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.springframework.restdocs.test;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* {@link Matcher Matchers} for verify the contents of generated documentation snippets.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class SnippetMatchers {
|
||||
|
||||
public static AsciidoctorTableMatcher tableWithHeader(String... headers) {
|
||||
return new AsciidoctorTableMatcher(headers);
|
||||
}
|
||||
|
||||
public static HttpRequestMatcher httpRequest(RequestMethod method, String uri) {
|
||||
return new HttpRequestMatcher(method, uri);
|
||||
}
|
||||
|
||||
public static HttpResponseMatcher httpResponse(HttpStatus status) {
|
||||
return new HttpResponseMatcher(status);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public static AsciidoctorCodeBlockMatcher<?> codeBlock(String language) {
|
||||
return new AsciidoctorCodeBlockMatcher(language);
|
||||
}
|
||||
|
||||
private static abstract class AbstractSnippetMatcher extends BaseMatcher<String> {
|
||||
|
||||
private List<String> lines = new ArrayList<String>();
|
||||
|
||||
protected void addLine(String line) {
|
||||
this.lines.add(line);
|
||||
}
|
||||
|
||||
protected void addLine(int index, String line) {
|
||||
if (index < 0) {
|
||||
index = index + this.lines.size();
|
||||
}
|
||||
this.lines.add(index, line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
return getLinesAsString().equals(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("Asciidoctor snippet");
|
||||
description.appendText(getLinesAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
description.appendText("was:");
|
||||
if (item instanceof String) {
|
||||
description.appendText((String) item);
|
||||
}
|
||||
else {
|
||||
description.appendValue(item);
|
||||
}
|
||||
}
|
||||
|
||||
private String getLinesAsString() {
|
||||
StringWriter writer = new StringWriter();
|
||||
for (String line : this.lines) {
|
||||
writer.append(String.format("%s%n", line));
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsciidoctorCodeBlockMatcher<T extends AsciidoctorCodeBlockMatcher<T>>
|
||||
extends AbstractSnippetMatcher {
|
||||
|
||||
protected AsciidoctorCodeBlockMatcher(String language) {
|
||||
this.addLine("");
|
||||
this.addLine("[source," + language + "]");
|
||||
this.addLine("----");
|
||||
this.addLine("----");
|
||||
this.addLine("");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T content(String content) {
|
||||
this.addLine(-2, content);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static abstract class HttpMatcher<T extends HttpMatcher<T>> extends
|
||||
AsciidoctorCodeBlockMatcher<HttpMatcher<T>> {
|
||||
|
||||
private int headerOffset = 4;
|
||||
|
||||
protected HttpMatcher() {
|
||||
super("http");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T header(String name, String value) {
|
||||
this.addLine(this.headerOffset++, name + ": " + value);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class HttpResponseMatcher extends HttpMatcher<HttpResponseMatcher> {
|
||||
|
||||
public HttpResponseMatcher(HttpStatus status) {
|
||||
this.content("HTTP/1.1 " + status.value() + " " + status.getReasonPhrase());
|
||||
this.content("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class HttpRequestMatcher extends HttpMatcher<HttpRequestMatcher> {
|
||||
|
||||
public HttpRequestMatcher(RequestMethod requestMethod, String uri) {
|
||||
this.content(requestMethod.name() + " " + uri + " HTTP/1.1");
|
||||
this.content("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class AsciidoctorTableMatcher extends AbstractSnippetMatcher {
|
||||
|
||||
private AsciidoctorTableMatcher(String... columns) {
|
||||
this.addLine("");
|
||||
this.addLine("|===");
|
||||
String header = "|"
|
||||
+ StringUtils
|
||||
.collectionToDelimitedString(Arrays.asList(columns), "|");
|
||||
this.addLine(header);
|
||||
this.addLine("");
|
||||
this.addLine("|===");
|
||||
this.addLine("");
|
||||
}
|
||||
|
||||
public AsciidoctorTableMatcher row(String... entries) {
|
||||
for (String entry : entries) {
|
||||
this.addLine(-2, "|" + entry);
|
||||
}
|
||||
this.addLine(-2, "");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs;
|
||||
package org.springframework.restdocs.test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.RequestBuilder;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
@@ -35,11 +37,43 @@ public class StubMvcResult implements MvcResult {
|
||||
|
||||
private final MockHttpServletResponse response;
|
||||
|
||||
public StubMvcResult(MockHttpServletRequest request, MockHttpServletResponse response) {
|
||||
public static StubMvcResult result() {
|
||||
return new StubMvcResult();
|
||||
}
|
||||
|
||||
public static StubMvcResult result(RequestBuilder requestBuilder) {
|
||||
return new StubMvcResult(requestBuilder);
|
||||
}
|
||||
|
||||
public static StubMvcResult result(MockHttpServletRequest request) {
|
||||
return new StubMvcResult(request);
|
||||
}
|
||||
|
||||
public static StubMvcResult result(MockHttpServletResponse response) {
|
||||
return new StubMvcResult(response);
|
||||
}
|
||||
|
||||
private StubMvcResult() {
|
||||
this(new MockHttpServletRequest(), new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
private StubMvcResult(MockHttpServletRequest request) {
|
||||
this(request, new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
private StubMvcResult(MockHttpServletResponse response) {
|
||||
this(new MockHttpServletRequest(), response);
|
||||
}
|
||||
|
||||
private StubMvcResult(MockHttpServletRequest request, MockHttpServletResponse response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
private StubMvcResult(RequestBuilder requestBuilder) {
|
||||
this(requestBuilder.buildRequest(new MockServletContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockHttpServletRequest getRequest() {
|
||||
return this.request;
|
||||
Reference in New Issue
Block a user