Allow users to control the writer that is used to produce each snippet
Previously, SnippetWritingResultHandler hard-coded its own logic for creating the Writer that used to write its snippet. This made it impossible to take complete control over the output location, filename suffix, etc. This commit introduces a new interface, WriterResolver, and a default implementation, StandardWriterResolver. It provides the same functionality as before, but SnippetWritingResultHandler now retrieves an instance of WriterResolver from the request's attributes. This allows users to provide their own WriterResolver implementation. Closes gh-100
This commit is contained in:
@@ -48,18 +48,18 @@ public final class ResponseModifier {
|
||||
/**
|
||||
* Provides a {@link RestDocumentationResultHandler} that can be used to document the
|
||||
* request and modified result.
|
||||
* @param outputDir The directory to which the documentation will be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @return the result handler that will produce the documentation
|
||||
*/
|
||||
public RestDocumentationResultHandler andDocument(String outputDir) {
|
||||
return new ResponseModifyingRestDocumentationResultHandler(outputDir);
|
||||
public RestDocumentationResultHandler andDocument(String identifier) {
|
||||
return new ResponseModifyingRestDocumentationResultHandler(identifier);
|
||||
}
|
||||
|
||||
class ResponseModifyingRestDocumentationResultHandler extends
|
||||
RestDocumentationResultHandler {
|
||||
|
||||
public ResponseModifyingRestDocumentationResultHandler(String outputDir) {
|
||||
super(outputDir);
|
||||
public ResponseModifyingRestDocumentationResultHandler(String identifier) {
|
||||
super(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,15 +47,15 @@ public abstract class RestDocumentation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call to the given {@code outputDir}.
|
||||
* Documents the API call using the given {@code identifier}.
|
||||
*
|
||||
* @param outputDir The directory to which the documentation will be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @return a Mock MVC {@code ResultHandler} that will produce the documentation
|
||||
* @see MockMvc#perform(org.springframework.test.web.servlet.RequestBuilder)
|
||||
* @see ResultActions#andDo(org.springframework.test.web.servlet.ResultHandler)
|
||||
*/
|
||||
public static RestDocumentationResultHandler document(String outputDir) {
|
||||
return new RestDocumentationResultHandler(outputDir);
|
||||
public static RestDocumentationResultHandler document(String identifier) {
|
||||
return new RestDocumentationResultHandler(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ import org.springframework.test.web.servlet.ResultHandler;
|
||||
*/
|
||||
public class RestDocumentationResultHandler implements ResultHandler {
|
||||
|
||||
private final String outputDir;
|
||||
private final String identifier;
|
||||
|
||||
private SnippetWritingResultHandler curlRequest;
|
||||
|
||||
@@ -59,11 +59,11 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
|
||||
private List<SnippetWritingResultHandler> delegates = new ArrayList<>();
|
||||
|
||||
RestDocumentationResultHandler(String outputDir) {
|
||||
this.outputDir = outputDir;
|
||||
this.curlRequest = documentCurlRequest(this.outputDir, null);
|
||||
this.httpRequest = documentHttpRequest(this.outputDir, null);
|
||||
this.httpResponse = documentHttpResponse(this.outputDir, null);
|
||||
RestDocumentationResultHandler(String identifier) {
|
||||
this.identifier = identifier;
|
||||
this.curlRequest = documentCurlRequest(this.identifier, null);
|
||||
this.httpRequest = documentHttpRequest(this.identifier, null);
|
||||
this.httpResponse = documentHttpResponse(this.identifier, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
* @return {@code this}
|
||||
*/
|
||||
public RestDocumentationResultHandler withCurlRequest(Map<String, Object> attributes) {
|
||||
this.curlRequest = documentCurlRequest(this.outputDir, attributes);
|
||||
this.curlRequest = documentCurlRequest(this.identifier, attributes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
* @return {@code this}
|
||||
*/
|
||||
public RestDocumentationResultHandler withHttpRequest(Map<String, Object> attributes) {
|
||||
this.httpRequest = documentHttpRequest(this.outputDir, attributes);
|
||||
this.httpRequest = documentHttpRequest(this.identifier, attributes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
* @return {@code this}
|
||||
*/
|
||||
public RestDocumentationResultHandler withHttpResponse(Map<String, Object> attributes) {
|
||||
this.httpResponse = documentHttpResponse(this.outputDir, attributes);
|
||||
this.httpResponse = documentHttpResponse(this.identifier, attributes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
*/
|
||||
public RestDocumentationResultHandler withLinks(Map<String, Object> attributes,
|
||||
LinkExtractor linkExtractor, LinkDescriptor... descriptors) {
|
||||
this.delegates.add(documentLinks(this.outputDir, attributes, linkExtractor,
|
||||
this.delegates.add(documentLinks(this.identifier, attributes, linkExtractor,
|
||||
descriptors));
|
||||
return this;
|
||||
}
|
||||
@@ -222,7 +222,7 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
public RestDocumentationResultHandler withRequestFields(
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
this.delegates
|
||||
.add(documentRequestFields(this.outputDir, attributes, descriptors));
|
||||
.add(documentRequestFields(this.identifier, attributes, descriptors));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -264,8 +264,8 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
*/
|
||||
public RestDocumentationResultHandler withResponseFields(
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
this.delegates
|
||||
.add(documentResponseFields(this.outputDir, attributes, descriptors));
|
||||
this.delegates.add(documentResponseFields(this.identifier, attributes,
|
||||
descriptors));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
*/
|
||||
public RestDocumentationResultHandler withQueryParameters(
|
||||
Map<String, Object> attributes, ParameterDescriptor... descriptors) {
|
||||
this.delegates.add(documentQueryParameters(this.outputDir, attributes,
|
||||
this.delegates.add(documentQueryParameters(this.identifier, attributes,
|
||||
descriptors));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ import java.util.List;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.RestDocumentation;
|
||||
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver;
|
||||
import org.springframework.restdocs.snippet.StandardWriterResolver;
|
||||
import org.springframework.restdocs.snippet.WriterResolver;
|
||||
import org.springframework.restdocs.templates.StandardTemplateResourceResolver;
|
||||
import org.springframework.restdocs.templates.TemplateEngine;
|
||||
import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
|
||||
@@ -49,6 +52,8 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter {
|
||||
|
||||
private TemplateEngineConfigurer templateEngineConfigurer = new TemplateEngineConfigurer();
|
||||
|
||||
private WriterResolverConfigurer writerResolverConfigurer = new WriterResolverConfigurer();
|
||||
|
||||
/**
|
||||
* Creates a new {@link RestDocumentationConfigurer}.
|
||||
* @see RestDocumentation#documentationConfiguration()
|
||||
@@ -56,9 +61,9 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter {
|
||||
public RestDocumentationConfigurer() {
|
||||
this.requestPostProcessor = new ConfigurerApplyingRequestPostProcessor(
|
||||
Arrays.<AbstractConfigurer> asList(this.uriConfigurer,
|
||||
this.snippetConfigurer, new StepCountConfigurer(),
|
||||
new ContentLengthHeaderConfigurer(),
|
||||
new TemplateEngineConfigurer()));
|
||||
this.writerResolverConfigurer, this.snippetConfigurer,
|
||||
new StepCountConfigurer(), new ContentLengthHeaderConfigurer(),
|
||||
this.templateEngineConfigurer));
|
||||
}
|
||||
|
||||
public UriConfigurer uris() {
|
||||
@@ -74,6 +79,11 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter {
|
||||
return this;
|
||||
}
|
||||
|
||||
public RestDocumentationConfigurer writerResolver(WriterResolver writerResolver) {
|
||||
this.writerResolverConfigurer.setWriterResolver(writerResolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPostProcessor beforeMockMvcCreated(
|
||||
ConfigurableMockMvcBuilder<?> builder, WebApplicationContext context) {
|
||||
@@ -84,10 +94,10 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
RestDocumentationContext currentContext = RestDocumentationContext
|
||||
.currentContext();
|
||||
if (currentContext != null) {
|
||||
currentContext.getAndIncrementStepCount();
|
||||
RestDocumentationContext context = (RestDocumentationContext) request
|
||||
.getAttribute(RestDocumentationContext.class.getName());
|
||||
if (context != null) {
|
||||
context.getAndIncrementStepCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +132,29 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter {
|
||||
|
||||
}
|
||||
|
||||
private static class WriterResolverConfigurer extends AbstractConfigurer {
|
||||
|
||||
private WriterResolver writerResolver;
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
WriterResolver resolverToUse = this.writerResolver;
|
||||
if (resolverToUse == null) {
|
||||
resolverToUse = new StandardWriterResolver(
|
||||
new RestDocumentationContextPlaceholderResolver(
|
||||
(RestDocumentationContext) request
|
||||
.getAttribute(RestDocumentationContext.class
|
||||
.getName())));
|
||||
}
|
||||
request.setAttribute(WriterResolver.class.getName(), resolverToUse);
|
||||
}
|
||||
|
||||
void setWriterResolver(WriterResolver writerResolver) {
|
||||
this.writerResolver = writerResolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ConfigurerApplyingRequestPostProcessor implements
|
||||
RequestPostProcessor {
|
||||
|
||||
@@ -134,6 +167,8 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||
request.setAttribute(RestDocumentationContext.class.getName(),
|
||||
RestDocumentationContextHolder.getCurrentContext());
|
||||
for (AbstractConfigurer configurer : this.configurers) {
|
||||
configurer.apply(request);
|
||||
}
|
||||
|
||||
@@ -19,42 +19,40 @@ package org.springframework.restdocs.config;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.springframework.test.context.TestContext;
|
||||
|
||||
/**
|
||||
* {@code RestDocumentationContext} encapsulates the context in which the documentation of
|
||||
* a RESTful API is being performed.
|
||||
*
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public final class RestDocumentationContext {
|
||||
|
||||
private static final ThreadLocal<RestDocumentationContext> CONTEXTS = new InheritableThreadLocal<RestDocumentationContext>();
|
||||
|
||||
private final AtomicInteger stepCount = new AtomicInteger(0);
|
||||
|
||||
private final Method testMethod;
|
||||
private final TestContext testContext;
|
||||
|
||||
private String snippetEncoding;
|
||||
|
||||
private RestDocumentationContext() {
|
||||
public RestDocumentationContext() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
private RestDocumentationContext(Method testMethod) {
|
||||
this.testMethod = testMethod;
|
||||
public RestDocumentationContext(TestContext testContext) {
|
||||
this.testContext = testContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test {@link Method method} that is currently executing
|
||||
*
|
||||
*
|
||||
* @return The test method
|
||||
*/
|
||||
public Method getTestMethod() {
|
||||
return this.testMethod;
|
||||
return this.testContext == null ? null : this.testContext.getTestMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and then increments the current step count
|
||||
*
|
||||
*
|
||||
* @return The step count prior to it being incremented
|
||||
*/
|
||||
int getAndIncrementStepCount() {
|
||||
@@ -63,41 +61,11 @@ public final class RestDocumentationContext {
|
||||
|
||||
/**
|
||||
* Gets the current step count
|
||||
*
|
||||
*
|
||||
* @return The current step count
|
||||
*/
|
||||
public int getStepCount() {
|
||||
return this.stepCount.get();
|
||||
}
|
||||
|
||||
void setSnippetEncoding(String snippetEncoding) {
|
||||
this.snippetEncoding = snippetEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the encoding to be used when writing snippets
|
||||
*
|
||||
* @return The snippet encoding
|
||||
*/
|
||||
public String getSnippetEncoding() {
|
||||
return this.snippetEncoding;
|
||||
}
|
||||
|
||||
static void establishContext(Method testMethod) {
|
||||
CONTEXTS.set(new RestDocumentationContext(testMethod));
|
||||
}
|
||||
|
||||
static void clearContext() {
|
||||
CONTEXTS.set(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current context, never {@code null}.
|
||||
*
|
||||
* @return The current context
|
||||
*/
|
||||
public static RestDocumentationContext currentContext() {
|
||||
return CONTEXTS.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.springframework.core.NamedInheritableThreadLocal;
|
||||
|
||||
final class RestDocumentationContextHolder {
|
||||
|
||||
private static final NamedInheritableThreadLocal<RestDocumentationContext> currentContext = new NamedInheritableThreadLocal<>(
|
||||
"REST Documentation Context");
|
||||
|
||||
private RestDocumentationContextHolder() {
|
||||
|
||||
}
|
||||
|
||||
static RestDocumentationContext getCurrentContext() {
|
||||
return currentContext.get();
|
||||
}
|
||||
|
||||
static void setCurrentContext(RestDocumentationContext context) {
|
||||
currentContext.set(context);
|
||||
}
|
||||
|
||||
static void removeCurrentContext() {
|
||||
currentContext.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,11 +30,12 @@ public class RestDocumentationTestExecutionListener extends AbstractTestExecutio
|
||||
|
||||
@Override
|
||||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
RestDocumentationContext.establishContext(testContext.getTestMethod());
|
||||
RestDocumentationContextHolder.setCurrentContext(new RestDocumentationContext(
|
||||
testContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
RestDocumentationContext.clearContext();
|
||||
RestDocumentationContextHolder.removeCurrentContext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.restdocs.config;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.snippet.WriterResolver;
|
||||
|
||||
/**
|
||||
* A configurer that can be used to configure the generated documentation snippets.
|
||||
@@ -52,10 +53,7 @@ public class SnippetConfigurer extends
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
RestDocumentationContext context = RestDocumentationContext.currentContext();
|
||||
if (context != null) {
|
||||
context.setSnippetEncoding(this.snippetEncoding);
|
||||
}
|
||||
((WriterResolver) request.getAttribute(WriterResolver.class.getName()))
|
||||
.setEncoding(this.snippetEncoding);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ public abstract class CurlDocumentation {
|
||||
/**
|
||||
* Produces a documentation snippet containing the request formatted as a cURL command
|
||||
*
|
||||
* @param outputDir The directory to which snippet should be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @param attributes Attributes made available during rendering of the curl request
|
||||
* snippet
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static SnippetWritingResultHandler documentCurlRequest(String outputDir,
|
||||
public static SnippetWritingResultHandler documentCurlRequest(String identifier,
|
||||
Map<String, Object> attributes) {
|
||||
return new CurlRequestWritingResultHandler(outputDir, attributes);
|
||||
return new CurlRequestWritingResultHandler(identifier, attributes);
|
||||
}
|
||||
|
||||
private static final class CurlRequestWritingResultHandler extends
|
||||
@@ -70,9 +70,9 @@ public abstract class CurlDocumentation {
|
||||
|
||||
private static final int STANDARD_PORT_HTTPS = 443;
|
||||
|
||||
private CurlRequestWritingResultHandler(String outputDir,
|
||||
private CurlRequestWritingResultHandler(String identifier,
|
||||
Map<String, Object> attributes) {
|
||||
super(outputDir, "curl-request", attributes);
|
||||
super(identifier, "curl-request", attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -53,37 +53,37 @@ public abstract class HttpDocumentation {
|
||||
* Produces a documentation snippet containing the request formatted as an HTTP
|
||||
* request
|
||||
*
|
||||
* @param outputDir The directory to which snippet should be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @param attributes Attributes made available during rendering of the HTTP requst
|
||||
* snippet
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static SnippetWritingResultHandler documentHttpRequest(String outputDir,
|
||||
public static SnippetWritingResultHandler documentHttpRequest(String identifier,
|
||||
Map<String, Object> attributes) {
|
||||
return new HttpRequestWritingResultHandler(outputDir, attributes);
|
||||
return new HttpRequestWritingResultHandler(identifier, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a documentation snippet containing the response formatted as the HTTP
|
||||
* response sent by the server
|
||||
*
|
||||
* @param outputDir The directory to which snippet should be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @param attributes Attributes made available during rendering of the HTTP response
|
||||
* snippet
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static SnippetWritingResultHandler documentHttpResponse(String outputDir,
|
||||
public static SnippetWritingResultHandler documentHttpResponse(String identifier,
|
||||
Map<String, Object> attributes) {
|
||||
return new HttpResponseWritingResultHandler(outputDir, attributes);
|
||||
return new HttpResponseWritingResultHandler(identifier, attributes);
|
||||
|
||||
}
|
||||
|
||||
private static final class HttpRequestWritingResultHandler extends
|
||||
SnippetWritingResultHandler {
|
||||
|
||||
private HttpRequestWritingResultHandler(String outputDir,
|
||||
private HttpRequestWritingResultHandler(String identifier,
|
||||
Map<String, Object> attributes) {
|
||||
super(outputDir, "http-request", attributes);
|
||||
super(identifier, "http-request", attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,9 +219,9 @@ public abstract class HttpDocumentation {
|
||||
private static final class HttpResponseWritingResultHandler extends
|
||||
SnippetWritingResultHandler {
|
||||
|
||||
private HttpResponseWritingResultHandler(String outputDir,
|
||||
private HttpResponseWritingResultHandler(String identifier,
|
||||
Map<String, Object> attributes) {
|
||||
super(outputDir, "http-response", attributes);
|
||||
super(identifier, "http-response", attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class HypermediaDocumentation {
|
||||
* Creates a {@code LinkSnippetResultHandler} that will produce a documentation
|
||||
* snippet for a response's links.
|
||||
*
|
||||
* @param outputDir The directory to which the snippet should be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @param attributes Attributes made available during rendering of the links snippet
|
||||
* @param linkExtractor Used to extract the links from the response
|
||||
* @param descriptors The descriptions of the response's links
|
||||
@@ -56,10 +56,10 @@ public abstract class HypermediaDocumentation {
|
||||
* @see RestDocumentationResultHandler#withLinks(LinkDescriptor...)
|
||||
* @see RestDocumentationResultHandler#withLinks(LinkExtractor, LinkDescriptor...)
|
||||
*/
|
||||
public static LinkSnippetResultHandler documentLinks(String outputDir,
|
||||
public static LinkSnippetResultHandler documentLinks(String identifier,
|
||||
Map<String, Object> attributes, LinkExtractor linkExtractor,
|
||||
LinkDescriptor... descriptors) {
|
||||
return new LinkSnippetResultHandler(outputDir, attributes, linkExtractor,
|
||||
return new LinkSnippetResultHandler(identifier, attributes, linkExtractor,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,9 +47,9 @@ public class LinkSnippetResultHandler extends SnippetWritingResultHandler {
|
||||
|
||||
private final LinkExtractor extractor;
|
||||
|
||||
LinkSnippetResultHandler(String outputDir, Map<String, Object> attributes,
|
||||
LinkSnippetResultHandler(String identifier, Map<String, Object> attributes,
|
||||
LinkExtractor linkExtractor, List<LinkDescriptor> descriptors) {
|
||||
super(outputDir, "links", attributes);
|
||||
super(identifier, "links", attributes);
|
||||
this.extractor = linkExtractor;
|
||||
for (LinkDescriptor descriptor : descriptors) {
|
||||
Assert.hasText(descriptor.getRel());
|
||||
|
||||
@@ -54,9 +54,9 @@ public abstract class FieldSnippetResultHandler extends SnippetWritingResultHand
|
||||
|
||||
private List<FieldDescriptor> fieldDescriptors;
|
||||
|
||||
FieldSnippetResultHandler(String outputDir, String type,
|
||||
FieldSnippetResultHandler(String identifier, String type,
|
||||
Map<String, Object> attributes, List<FieldDescriptor> descriptors) {
|
||||
super(outputDir, type + "-fields", attributes);
|
||||
super(identifier, type + "-fields", attributes);
|
||||
this.templateName = type + "-fields";
|
||||
for (FieldDescriptor descriptor : descriptors) {
|
||||
Assert.notNull(descriptor.getPath());
|
||||
|
||||
@@ -107,16 +107,16 @@ public abstract class PayloadDocumentation {
|
||||
* field is sufficient for all of its descendants to also be treated as having been
|
||||
* documented.
|
||||
*
|
||||
* @param outputDir The directory to which the snippet should be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @param attributes Attributes made available during rendering of the links snippet
|
||||
* @param descriptors The descriptions of the request's fields
|
||||
* @return the handler
|
||||
* @see RestDocumentationResultHandler#withRequestFields(FieldDescriptor...)
|
||||
* @see #fieldWithPath(String)
|
||||
*/
|
||||
public static FieldSnippetResultHandler documentRequestFields(String outputDir,
|
||||
public static FieldSnippetResultHandler documentRequestFields(String identifier,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return new RequestFieldSnippetResultHandler(outputDir, attributes,
|
||||
return new RequestFieldSnippetResultHandler(identifier, attributes,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
@@ -131,15 +131,15 @@ public abstract class PayloadDocumentation {
|
||||
* field is sufficient for all of its descendants to also be treated as having been
|
||||
* documented.
|
||||
*
|
||||
* @param outputDir The directory to which the snippet should be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @param attributes Attributes made available during rendering of the links snippet
|
||||
* @param descriptors The descriptions of the response's fields
|
||||
* @return the handler
|
||||
* @see RestDocumentationResultHandler#withResponseFields(FieldDescriptor...)
|
||||
*/
|
||||
public static FieldSnippetResultHandler documentResponseFields(String outputDir,
|
||||
public static FieldSnippetResultHandler documentResponseFields(String identifier,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return new ResponseFieldSnippetResultHandler(outputDir, attributes,
|
||||
return new ResponseFieldSnippetResultHandler(identifier, attributes,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,9 @@ import org.springframework.test.web.servlet.MvcResult;
|
||||
*/
|
||||
public class RequestFieldSnippetResultHandler extends FieldSnippetResultHandler {
|
||||
|
||||
RequestFieldSnippetResultHandler(String outputDir, Map<String, Object> attributes,
|
||||
RequestFieldSnippetResultHandler(String identifier, Map<String, Object> attributes,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
super(outputDir, "request", attributes, descriptors);
|
||||
super(identifier, "request", attributes, descriptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,9 +30,9 @@ import org.springframework.test.web.servlet.MvcResult;
|
||||
*/
|
||||
public class ResponseFieldSnippetResultHandler extends FieldSnippetResultHandler {
|
||||
|
||||
ResponseFieldSnippetResultHandler(String outputDir, Map<String, Object> attributes,
|
||||
ResponseFieldSnippetResultHandler(String identifier, Map<String, Object> attributes,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
super(outputDir, "response", attributes, descriptors);
|
||||
super(identifier, "response", attributes, descriptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,9 +43,9 @@ public class QueryParametersSnippetResultHandler extends SnippetWritingResultHan
|
||||
|
||||
private final Map<String, ParameterDescriptor> descriptorsByName = new LinkedHashMap<>();
|
||||
|
||||
protected QueryParametersSnippetResultHandler(String outputDir,
|
||||
protected QueryParametersSnippetResultHandler(String identifier,
|
||||
Map<String, Object> attributes, ParameterDescriptor... descriptors) {
|
||||
super(outputDir, "query-parameters", attributes);
|
||||
super(identifier, "query-parameters", attributes);
|
||||
for (ParameterDescriptor descriptor : descriptors) {
|
||||
Assert.hasText(descriptor.getName());
|
||||
Assert.hasText(descriptor.getDescription());
|
||||
|
||||
@@ -36,16 +36,17 @@ public abstract class RequestDocumentation {
|
||||
* Creates a {@link SnippetWritingResultHandler} that will produce a snippet
|
||||
* documenting a request's query parameters
|
||||
*
|
||||
* @param outputDir The directory to which the snippet should be written
|
||||
* @param identifier An identifier for the API call that is being documented
|
||||
* @param attributes Attributes made available during rendering of the query
|
||||
* parameters snippet
|
||||
* @param descriptors The descriptions of the parameters in the request's query string
|
||||
* @return the result handler
|
||||
* @see RestDocumentationResultHandler#withQueryParameters(ParameterDescriptor...)
|
||||
*/
|
||||
public static SnippetWritingResultHandler documentQueryParameters(String outputDir,
|
||||
public static SnippetWritingResultHandler documentQueryParameters(String identifier,
|
||||
Map<String, Object> attributes, ParameterDescriptor... descriptors) {
|
||||
return new QueryParametersSnippetResultHandler(outputDir, attributes, descriptors);
|
||||
return new QueryParametersSnippetResultHandler(identifier, attributes,
|
||||
descriptors);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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.snippet;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.restdocs.config.RestDocumentationContext;
|
||||
|
||||
/**
|
||||
* {@code OutputFileResolver} resolves an absolute output file based on the current
|
||||
* configuration and context.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class OutputFileResolver {
|
||||
|
||||
private static final Pattern CAMEL_CASE_PATTERN = Pattern.compile("([A-Z])");
|
||||
|
||||
File resolve(String outputDirectory, String fileName) {
|
||||
Map<String, String> replacements = createReplacements();
|
||||
String path = outputDirectory;
|
||||
for (Entry<String, String> replacement : replacements.entrySet()) {
|
||||
while (path.contains(replacement.getKey())) {
|
||||
if (replacement.getValue() == null) {
|
||||
throw new IllegalStateException("No replacement is available for "
|
||||
+ replacement.getKey());
|
||||
}
|
||||
else {
|
||||
path = path.replace(replacement.getKey(), replacement.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File outputFile = new File(path, fileName);
|
||||
if (!outputFile.isAbsolute()) {
|
||||
outputFile = makeRelativeToConfiguredOutputDir(outputFile);
|
||||
}
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
private Map<String, String> createReplacements() {
|
||||
RestDocumentationContext context = RestDocumentationContext.currentContext();
|
||||
|
||||
Map<String, String> replacements = new HashMap<String, String>();
|
||||
replacements.put("{methodName}", context == null ? null : context.getTestMethod()
|
||||
.getName());
|
||||
replacements.put("{method-name}", context == null ? null
|
||||
: camelCaseToDash(context.getTestMethod().getName()));
|
||||
replacements.put("{method_name}", context == null ? null
|
||||
: camelCaseToUnderscore(context.getTestMethod().getName()));
|
||||
replacements.put("{step}",
|
||||
context == null ? null : Integer.toString(context.getStepCount()));
|
||||
|
||||
return replacements;
|
||||
}
|
||||
|
||||
private String camelCaseToDash(String string) {
|
||||
return camelCaseToSeparator(string, "-");
|
||||
}
|
||||
|
||||
private String camelCaseToUnderscore(String string) {
|
||||
return camelCaseToSeparator(string, "_");
|
||||
}
|
||||
|
||||
private String camelCaseToSeparator(String string, String separator) {
|
||||
Matcher matcher = CAMEL_CASE_PATTERN.matcher(string);
|
||||
StringBuffer result = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
matcher.appendReplacement(result, separator + matcher.group(1).toLowerCase());
|
||||
}
|
||||
matcher.appendTail(result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private File makeRelativeToConfiguredOutputDir(File outputFile) {
|
||||
File configuredOutputDir = new DocumentationProperties().getOutputDir();
|
||||
if (configuredOutputDir != null) {
|
||||
return new File(configuredOutputDir, outputFile.getPath());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.snippet;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.restdocs.config.RestDocumentationContext;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
|
||||
/**
|
||||
* A {@link PlaceholderResolver} that resolves placeholders using a
|
||||
* {@link RestDocumentationContext}. The following placeholders are supported:
|
||||
* <ul>
|
||||
* <li>{@code step} – the {@link RestDocumentationContext#getStepCount() step current
|
||||
* count}.
|
||||
* <li>{@code methodName} - the name of the
|
||||
* {@link RestDocumentationContext#getTestMethod() current test method} formatted using
|
||||
* camelCase
|
||||
* <li>{@code method-name} - the name of the
|
||||
* {@link RestDocumentationContext#getTestMethod() current test method} formatted using
|
||||
* kebab-case
|
||||
* <li>{@code method_name} - the name of the
|
||||
* {@link RestDocumentationContext#getTestMethod() current test method} formatted using
|
||||
* snake_case
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class RestDocumentationContextPlaceholderResolver implements PlaceholderResolver {
|
||||
|
||||
private static final Pattern CAMEL_CASE_PATTERN = Pattern.compile("([A-Z])");
|
||||
|
||||
private final RestDocumentationContext context;
|
||||
|
||||
public RestDocumentationContextPlaceholderResolver(RestDocumentationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolvePlaceholder(String placeholderName) {
|
||||
if ("step".equals(placeholderName)) {
|
||||
return Integer.toString(this.context.getStepCount());
|
||||
}
|
||||
if ("methodName".equals(placeholderName)) {
|
||||
return this.context.getTestMethod().getName();
|
||||
}
|
||||
if ("method-name".equals(placeholderName)) {
|
||||
return camelCaseToDash(this.context.getTestMethod().getName());
|
||||
}
|
||||
if ("method_name".equals(placeholderName)) {
|
||||
return camelCaseToUnderscore(this.context.getTestMethod().getName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String camelCaseToDash(String string) {
|
||||
return camelCaseToSeparator(string, "-");
|
||||
}
|
||||
|
||||
private String camelCaseToUnderscore(String string) {
|
||||
return camelCaseToSeparator(string, "_");
|
||||
}
|
||||
|
||||
private String camelCaseToSeparator(String string, String separator) {
|
||||
Matcher matcher = CAMEL_CASE_PATTERN.matcher(string);
|
||||
StringBuffer result = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
matcher.appendReplacement(result, separator + matcher.group(1).toLowerCase());
|
||||
}
|
||||
matcher.appendTail(result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,37 +16,32 @@
|
||||
|
||||
package org.springframework.restdocs.snippet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.restdocs.config.RestDocumentationContext;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultHandler;
|
||||
|
||||
/**
|
||||
* Base class for a {@link ResultHandler} that writes a documentation snippet
|
||||
*
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public abstract class SnippetWritingResultHandler implements ResultHandler {
|
||||
|
||||
private final Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
private final String outputDir;
|
||||
private final String identifier;
|
||||
|
||||
private final String fileName;
|
||||
private final String snippetName;
|
||||
|
||||
protected SnippetWritingResultHandler(String outputDir, String fileName,
|
||||
protected SnippetWritingResultHandler(String identifier, String snippetName,
|
||||
Map<String, Object> attributes) {
|
||||
this.outputDir = outputDir;
|
||||
this.fileName = fileName;
|
||||
this.identifier = identifier;
|
||||
this.snippetName = snippetName;
|
||||
if (attributes != null) {
|
||||
this.attributes.putAll(attributes);
|
||||
}
|
||||
@@ -57,7 +52,9 @@ public abstract class SnippetWritingResultHandler implements ResultHandler {
|
||||
|
||||
@Override
|
||||
public void handle(MvcResult result) throws IOException {
|
||||
try (Writer writer = createWriter()) {
|
||||
WriterResolver writerResolver = (WriterResolver) result.getRequest()
|
||||
.getAttribute(WriterResolver.class.getName());
|
||||
try (Writer writer = writerResolver.resolve(this.identifier, this.snippetName)) {
|
||||
handle(result, new PrintWriter(writer));
|
||||
}
|
||||
}
|
||||
@@ -66,26 +63,4 @@ public abstract class SnippetWritingResultHandler implements ResultHandler {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
private Writer createWriter() throws IOException {
|
||||
File outputFile = new OutputFileResolver().resolve(this.outputDir, this.fileName
|
||||
+ ".adoc");
|
||||
|
||||
if (outputFile != null) {
|
||||
File parent = outputFile.getParentFile();
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
throw new IllegalStateException("Failed to create directory '" + parent
|
||||
+ "'");
|
||||
}
|
||||
RestDocumentationContext context = RestDocumentationContext.currentContext();
|
||||
if (context == null || context.getSnippetEncoding() == null) {
|
||||
return new FileWriter(outputFile);
|
||||
}
|
||||
return new OutputStreamWriter(new FileOutputStream(outputFile),
|
||||
context.getSnippetEncoding());
|
||||
}
|
||||
else {
|
||||
return new OutputStreamWriter(System.out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.snippet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
|
||||
/**
|
||||
* Standard implementation of {@link WriterResolver}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class StandardWriterResolver implements WriterResolver {
|
||||
|
||||
private String encoding = "UTF-8";
|
||||
|
||||
private final PlaceholderResolver placeholderResolver;
|
||||
|
||||
private final PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper(
|
||||
"{", "}");
|
||||
|
||||
/**
|
||||
* Creates a new {@code StandardWriterResolver} that will use the given
|
||||
* {@code placeholderResolver} to resolve any placeholders in the
|
||||
* {@code operationName}.
|
||||
*
|
||||
* @param placeholderResolver the placeholder resolver
|
||||
*/
|
||||
public StandardWriterResolver(PlaceholderResolver placeholderResolver) {
|
||||
this.placeholderResolver = placeholderResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer resolve(String operationName, String snippetName) throws IOException {
|
||||
File outputFile = resolveFile(this.propertyPlaceholderHelper.replacePlaceholders(
|
||||
operationName, this.placeholderResolver), snippetName + ".adoc");
|
||||
|
||||
if (outputFile != null) {
|
||||
createDirectoriesIfNecessary(outputFile);
|
||||
return new OutputStreamWriter(new FileOutputStream(outputFile), this.encoding);
|
||||
}
|
||||
else {
|
||||
return new OutputStreamWriter(System.out, this.encoding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEncoding(String encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
protected File resolveFile(String outputDirectory, String fileName) {
|
||||
File outputFile = new File(outputDirectory, fileName);
|
||||
if (!outputFile.isAbsolute()) {
|
||||
outputFile = makeRelativeToConfiguredOutputDir(outputFile);
|
||||
}
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
private File makeRelativeToConfiguredOutputDir(File outputFile) {
|
||||
File configuredOutputDir = new DocumentationProperties().getOutputDir();
|
||||
if (configuredOutputDir != null) {
|
||||
return new File(configuredOutputDir, outputFile.getPath());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void createDirectoriesIfNecessary(File outputFile) {
|
||||
File parent = outputFile.getParentFile();
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
throw new IllegalStateException("Failed to create directory '" + parent + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.snippet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* A {@code WriterResolver} is used to access the {@link Writer} that should be used to
|
||||
* write a snippet for an operation that is being documented.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface WriterResolver {
|
||||
|
||||
/**
|
||||
* Returns a writer that can be used to write the snippet with the given name for the
|
||||
* operation with the given name.
|
||||
* @param operationName the name of the operation that is being documented
|
||||
* @param snippetName the name of the snippet
|
||||
* @return the writer
|
||||
* @throws IOException if a writer cannot be resolved
|
||||
*/
|
||||
Writer resolve(String operationName, String snippetName) throws IOException;
|
||||
|
||||
/**
|
||||
* Configures the encoding that should be used by any writers produced by this
|
||||
* resolver
|
||||
* @param encoding the encoding
|
||||
*/
|
||||
void setEncoding(String encoding);
|
||||
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.restdocs.Attributes.attributes;
|
||||
import static org.springframework.restdocs.Attributes.key;
|
||||
import static org.springframework.restdocs.RestDocumentation.document;
|
||||
import static org.springframework.restdocs.RestDocumentation.modifyResponseTo;
|
||||
import static org.springframework.restdocs.response.ResponsePostProcessors.maskLinks;
|
||||
@@ -199,6 +201,10 @@ public class RestDocumentationIntegrationTests {
|
||||
assertThat(new File(
|
||||
"build/generated-snippets/custom-snippet-template/curl-request.adoc"),
|
||||
is(snippet().withContents(equalTo("Custom curl request"))));
|
||||
|
||||
mockMvc.perform(get("/")).andDo(
|
||||
document("index").withCurlRequest(
|
||||
attributes(key("title").value("Access the index using curl"))));
|
||||
}
|
||||
|
||||
private void assertExpectedSnippetFilesExist(File directory, String... snippets) {
|
||||
|
||||
@@ -24,6 +24,8 @@ import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.mvc.BasicLinkBuilder;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
@@ -41,6 +43,18 @@ public class RestDocumentationConfigurerTests {
|
||||
|
||||
private MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
private RestDocumentationContext context = new RestDocumentationContext();
|
||||
|
||||
@Before
|
||||
public void establishContext() {
|
||||
RestDocumentationContextHolder.setCurrentContext(this.context);
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearContext() {
|
||||
RestDocumentationContextHolder.removeCurrentContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultConfiguration() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationConfigurer()
|
||||
@@ -118,38 +132,6 @@ public class RestDocumentationConfigurerTests {
|
||||
is(equalTo(Integer.toString(content.length))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultSnippetEncodingIsAppliedToTheContext() {
|
||||
RestDocumentationContext.establishContext(null);
|
||||
try {
|
||||
assertThat(RestDocumentationContext.currentContext().getSnippetEncoding(),
|
||||
is(nullValue()));
|
||||
new RestDocumentationConfigurer().beforeMockMvcCreated(null, null)
|
||||
.postProcessRequest(this.request);
|
||||
assertThat(RestDocumentationContext.currentContext().getSnippetEncoding(),
|
||||
is(equalTo("UTF-8")));
|
||||
}
|
||||
finally {
|
||||
RestDocumentationContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customSnippetEncodingIsAppliedToTheContext() {
|
||||
RestDocumentationContext.establishContext(null);
|
||||
try {
|
||||
assertThat(RestDocumentationContext.currentContext().getSnippetEncoding(),
|
||||
is(nullValue()));
|
||||
new RestDocumentationConfigurer().snippets().withEncoding("foo")
|
||||
.beforeMockMvcCreated(null, null).postProcessRequest(this.request);
|
||||
assertThat(RestDocumentationContext.currentContext().getSnippetEncoding(),
|
||||
is(equalTo("foo")));
|
||||
}
|
||||
finally {
|
||||
RestDocumentationContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertUriConfiguration(String scheme, String host, int port) {
|
||||
assertEquals(scheme, this.request.getScheme());
|
||||
assertEquals(host, this.request.getServerName());
|
||||
|
||||
@@ -24,9 +24,9 @@ import static org.springframework.restdocs.Attributes.attributes;
|
||||
import static org.springframework.restdocs.Attributes.key;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.documentQueryParameters;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.test.RestDocumentationRequestBuilders.get;
|
||||
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.IOException;
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.config.RestDocumentationContext;
|
||||
import org.springframework.restdocs.snippet.SnippetGenerationException;
|
||||
import org.springframework.restdocs.templates.TemplateEngine;
|
||||
import org.springframework.restdocs.templates.TemplateResourceResolver;
|
||||
@@ -43,7 +44,7 @@ import org.springframework.restdocs.test.ExpectedSnippet;
|
||||
|
||||
/**
|
||||
* Requests for {@link RequestDocumentation}
|
||||
*
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class RequestDocumentationTests {
|
||||
@@ -107,7 +108,9 @@ public class RequestDocumentationTests {
|
||||
documentQueryParameters("parameter-snippet-request-uri-query-string", null,
|
||||
parameterWithName("a").description("one"),
|
||||
parameterWithName("b").description("two")).handle(
|
||||
result(get("/?a=alpha&b=bravo")));
|
||||
result(get("/?a=alpha&b=bravo").requestAttr(
|
||||
RestDocumentationContext.class.getName(),
|
||||
new RestDocumentationContext())));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* 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.snippet;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.restdocs.config.RestDocumentationTestExecutionListener;
|
||||
import org.springframework.test.context.TestContext;
|
||||
|
||||
/**
|
||||
* Tests for {@link OutputFileResolver}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class OutputFileResolverTests {
|
||||
|
||||
private final OutputFileResolver resolver = new OutputFileResolver();
|
||||
|
||||
@Test
|
||||
public void noConfiguredOutputDirectoryAndRelativeInput() {
|
||||
assertThat(this.resolver.resolve("foo", "bar.txt"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void absoluteInput() {
|
||||
String absolutePath = new File("foo").getAbsolutePath();
|
||||
assertThat(this.resolver.resolve(absolutePath, "bar.txt"), is(new File(
|
||||
absolutePath, "bar.txt")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuredOutputAndRelativeInput() {
|
||||
String outputDir = new File("foo").getAbsolutePath();
|
||||
System.setProperty("org.springframework.restdocs.outputDir", outputDir);
|
||||
try {
|
||||
assertThat(this.resolver.resolve("bar", "baz.txt"), is(new File(outputDir,
|
||||
"bar/baz.txt")));
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuredOutputAndAbsoluteInput() {
|
||||
String outputDir = new File("foo").getAbsolutePath();
|
||||
String absolutePath = new File("bar").getAbsolutePath();
|
||||
System.setProperty("org.springframework.restdocs.outputDir", outputDir);
|
||||
try {
|
||||
assertThat(this.resolver.resolve(absolutePath, "baz.txt"), is(new File(
|
||||
absolutePath, "baz.txt")));
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void placeholderWithoutAReplacement() {
|
||||
this.resolver.resolve("{method-name}", "foo.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dashSeparatedMethodName() throws Exception {
|
||||
RestDocumentationTestExecutionListener listener = new RestDocumentationTestExecutionListener();
|
||||
TestContext testContext = mock(TestContext.class);
|
||||
Method method = getClass().getMethod("dashSeparatedMethodName");
|
||||
when(testContext.getTestMethod()).thenReturn(method);
|
||||
listener.beforeTestMethod(testContext);
|
||||
try {
|
||||
assertThat(this.resolver.resolve(new File("{method-name}").getAbsolutePath(),
|
||||
"foo.txt"),
|
||||
is(new File(new File("dash-separated-method-name").getAbsolutePath(),
|
||||
"foo.txt")));
|
||||
}
|
||||
finally {
|
||||
listener.afterTestMethod(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void underscoreSeparatedMethodName() throws Exception {
|
||||
RestDocumentationTestExecutionListener listener = new RestDocumentationTestExecutionListener();
|
||||
TestContext testContext = mock(TestContext.class);
|
||||
Method method = getClass().getMethod("underscoreSeparatedMethodName");
|
||||
when(testContext.getTestMethod()).thenReturn(method);
|
||||
listener.beforeTestMethod(testContext);
|
||||
try {
|
||||
assertThat(
|
||||
this.resolver.resolve(new File("{method_name}").getAbsolutePath(),
|
||||
"foo.txt"),
|
||||
is(new File(new File("underscore_separated_method_name")
|
||||
.getAbsolutePath(), "foo.txt")));
|
||||
}
|
||||
finally {
|
||||
listener.afterTestMethod(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void camelCaseMethodName() throws Exception {
|
||||
RestDocumentationTestExecutionListener listener = new RestDocumentationTestExecutionListener();
|
||||
TestContext testContext = mock(TestContext.class);
|
||||
Method method = getClass().getMethod("camelCaseMethodName");
|
||||
when(testContext.getTestMethod()).thenReturn(method);
|
||||
listener.beforeTestMethod(testContext);
|
||||
try {
|
||||
assertThat(this.resolver.resolve(new File("{methodName}").getAbsolutePath(),
|
||||
"foo.txt"),
|
||||
is(new File(new File("camelCaseMethodName").getAbsolutePath(),
|
||||
"foo.txt")));
|
||||
}
|
||||
finally {
|
||||
listener.afterTestMethod(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stepCount() throws Exception {
|
||||
RestDocumentationTestExecutionListener listener = new RestDocumentationTestExecutionListener();
|
||||
TestContext testContext = mock(TestContext.class);
|
||||
Method method = getClass().getMethod("stepCount");
|
||||
when(testContext.getTestMethod()).thenReturn(method);
|
||||
listener.beforeTestMethod(testContext);
|
||||
try {
|
||||
assertThat(this.resolver.resolve(new File("{step}").getAbsolutePath(),
|
||||
"foo.txt"), is(new File(new File("0").getAbsolutePath(), "foo.txt")));
|
||||
}
|
||||
finally {
|
||||
listener.afterTestMethod(testContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.springframework.restdocs.snippet;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.restdocs.config.RestDocumentationContext;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestDocumentationContextPlaceholderResolver}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*
|
||||
*/
|
||||
public class RestDocumentationContextPlaceholderResolverTests {
|
||||
|
||||
private final TestContext testContext = mock(TestContext.class);
|
||||
|
||||
private final RestDocumentationContext context = new RestDocumentationContext(
|
||||
this.testContext);
|
||||
|
||||
private final PlaceholderResolver resolver = new RestDocumentationContextPlaceholderResolver(
|
||||
this.context);
|
||||
|
||||
@Test
|
||||
public void dashSeparatedMethodName() throws Exception {
|
||||
when(this.testContext.getTestMethod()).thenReturn(
|
||||
getClass().getMethod("dashSeparatedMethodName"));
|
||||
assertThat(this.resolver.resolvePlaceholder("method-name"),
|
||||
equalTo("dash-separated-method-name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void underscoreSeparatedMethodName() throws Exception {
|
||||
when(this.testContext.getTestMethod()).thenReturn(
|
||||
getClass().getMethod("underscoreSeparatedMethodName"));
|
||||
assertThat(this.resolver.resolvePlaceholder("method_name"),
|
||||
equalTo("underscore_separated_method_name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void camelCaseMethodName() throws Exception {
|
||||
Method method = getClass().getMethod("camelCaseMethodName");
|
||||
when(this.testContext.getTestMethod()).thenReturn(method);
|
||||
assertThat(this.resolver.resolvePlaceholder("methodName"),
|
||||
equalTo("camelCaseMethodName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stepCount() throws Exception {
|
||||
assertThat(this.resolver.resolvePlaceholder("step"), equalTo("0"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.snippet;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
|
||||
/**
|
||||
* Tests for {@link StandardWriterResolver}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class StandardWriterResolverTests {
|
||||
|
||||
private final PlaceholderResolver placeholderResolver = mock(PlaceholderResolver.class);
|
||||
|
||||
private final StandardWriterResolver resolver = new StandardWriterResolver(
|
||||
this.placeholderResolver);
|
||||
|
||||
@Test
|
||||
public void noConfiguredOutputDirectoryAndRelativeInput() {
|
||||
assertThat(this.resolver.resolveFile("foo", "bar.txt"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void absoluteInput() {
|
||||
String absolutePath = new File("foo").getAbsolutePath();
|
||||
assertThat(this.resolver.resolveFile(absolutePath, "bar.txt"), is(new File(
|
||||
absolutePath, "bar.txt")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuredOutputAndRelativeInput() {
|
||||
String outputDir = new File("foo").getAbsolutePath();
|
||||
System.setProperty("org.springframework.restdocs.outputDir", outputDir);
|
||||
try {
|
||||
assertThat(this.resolver.resolveFile("bar", "baz.txt"), is(new File(
|
||||
outputDir, "bar/baz.txt")));
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuredOutputAndAbsoluteInput() {
|
||||
String outputDir = new File("foo").getAbsolutePath();
|
||||
String absolutePath = new File("bar").getAbsolutePath();
|
||||
System.setProperty("org.springframework.restdocs.outputDir", outputDir);
|
||||
try {
|
||||
assertThat(this.resolver.resolveFile(absolutePath, "baz.txt"), is(new File(
|
||||
absolutePath, "baz.txt")));
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.springframework.restdocs.test;
|
||||
|
||||
import org.springframework.restdocs.config.RestDocumentationContext;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
public class RestDocumentationRequestBuilders {
|
||||
|
||||
private RestDocumentationRequestBuilders() {
|
||||
|
||||
}
|
||||
|
||||
public static MockHttpServletRequestBuilder get(String urlTemplate) {
|
||||
return MockMvcRequestBuilders.get(urlTemplate).requestAttr(
|
||||
RestDocumentationContext.class.getName(), new RestDocumentationContext());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,10 @@ 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.restdocs.config.RestDocumentationContext;
|
||||
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver;
|
||||
import org.springframework.restdocs.snippet.StandardWriterResolver;
|
||||
import org.springframework.restdocs.snippet.WriterResolver;
|
||||
import org.springframework.restdocs.templates.StandardTemplateResourceResolver;
|
||||
import org.springframework.restdocs.templates.TemplateEngine;
|
||||
import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
|
||||
@@ -30,7 +34,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* A minimal stub implementation of {@link MvcResult}
|
||||
*
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*
|
||||
*/
|
||||
@@ -88,6 +92,13 @@ public class StubMvcResult implements MvcResult {
|
||||
this.request.setAttribute(TemplateEngine.class.getName(),
|
||||
new MustacheTemplateEngine(new StandardTemplateResourceResolver()));
|
||||
}
|
||||
RestDocumentationContext context = new RestDocumentationContext();
|
||||
this.request.setAttribute(RestDocumentationContext.class.getName(), context);
|
||||
if (this.request.getAttribute(WriterResolver.class.getName()) == null) {
|
||||
this.request.setAttribute(WriterResolver.class.getName(),
|
||||
new StandardWriterResolver(
|
||||
new RestDocumentationContextPlaceholderResolver(context)));
|
||||
}
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user