From 2b2b6fcd252d3df3af15c3b92e921e7b6b71c631 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 2 Sep 2015 16:20:34 +0100 Subject: [PATCH] Isolate and reduce Spring Test dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit splits Spring REST Docs into two projects – spring-restdocs-core and spring-restdocs-mockmvc. spring-restdocs-core contains the vast majority of the code but does not depend on a specific test framework other than JUnit. The use of a Spring Test TestExecutionListener has been replaced with a JUnit test rule. The rule is declared once per test class and configured with the output directory to which the generated snippets should be written. This simplifies the implementation as thread local storage is no longer required to transfer information about the test that’s running into Spring REST Docs. Instead, this transfer is now handled by the new test rule. It has also simplified the configuration as it’s no longer necessary for users to provide a system property that configures the output directory. spring-restdocs-mockmvc contains code that’s specific to using Spring REST Docs with Spring MVC Test’s MockMvc. This is currently the only testing framework that’s supported, but it paves the way for adding support for additional frameworks. REST Assured is one that users seem particularly interested in (see gh-80 and gh-102). Closes gh-107 --- build.gradle | 109 +++++++++++- .../build/SampleBuildConfigurer.groovy | 13 +- docs/build.gradle | 6 +- docs/src/docs/asciidoc/configuration.adoc | 20 --- docs/src/docs/asciidoc/getting-started.adoc | 68 ++++---- docs/src/test/java/com/example/AlwaysDo.java | 13 +- .../test/java/com/example/Constraints.java | 24 ++- .../CustomDefaultSnippetsConfiguration.java | 25 ++- .../test/java/com/example/CustomEncoding.java | 9 +- .../com/example/CustomUriConfiguration.java | 9 +- .../com/example/ExampleApplicationTests.java | 11 +- .../src/test/java/com/example/Hypermedia.java | 4 +- .../test/java/com/example/InvokeService.java | 4 +- .../test/java/com/example/PathParameters.java | 4 +- docs/src/test/java/com/example/Payload.java | 6 +- .../test/java/com/example/Preprocessing.java | 4 +- .../java/com/example/RequestParameters.java | 6 +- .../rest-notes-spring-data-rest/build.gradle | 68 -------- .../gradle/wrapper/gradle-wrapper.jar | Bin 51017 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - samples/rest-notes-spring-data-rest/gradlew | 164 ------------------ .../rest-notes-spring-data-rest/gradlew.bat | 90 ---------- samples/rest-notes-spring-data-rest/pom.xml | 9 +- .../com/example/notes/ApiDocumentation.java | 30 ++-- .../notes/GettingStartedDocumentation.java | 17 +- .../rest-notes-spring-hateoas/build.gradle | 7 +- samples/rest-notes-spring-hateoas/pom.xml | 137 --------------- .../com/example/notes/ApiDocumentation.java | 17 +- .../notes/GettingStartedDocumentation.java | 17 +- settings.gradle | 5 +- .../.settings/org.eclipse.jdt.core.prefs | 0 .../.settings/org.eclipse.jdt.ui.prefs | 0 spring-restdocs-core/build.gradle | 59 +++++++ .../restdocs/RestDocumentation.java | 81 +++++++++ .../restdocs/RestDocumentationContext.java | 99 +++++++++++ .../restdocs/constraints/Constraint.java | 0 .../ConstraintDescriptionResolver.java | 0 .../constraints/ConstraintDescriptions.java | 0 .../constraints/ConstraintResolver.java | 0 ...ceBundleConstraintDescriptionResolver.java | 0 .../ValidatorConstraintResolver.java | 0 .../restdocs/curl/CurlDocumentation.java | 0 .../restdocs/curl/CurlRequestSnippet.java | 0 .../restdocs/http/HttpDocumentation.java | 0 .../restdocs/http/HttpRequestSnippet.java | 0 .../restdocs/http/HttpResponseSnippet.java | 0 .../hypermedia/AbstractJsonLinkExtractor.java | 0 .../hypermedia/AtomLinkExtractor.java | 0 .../hypermedia/ContentTypeLinkExtractor.java | 18 +- .../restdocs/hypermedia/HalLinkExtractor.java | 0 .../hypermedia/HypermediaDocumentation.java | 0 .../restdocs/hypermedia/Link.java | 0 .../restdocs/hypermedia/LinkDescriptor.java | 0 .../restdocs/hypermedia/LinkExtractor.java | 0 .../restdocs/hypermedia/LinksSnippet.java | 0 .../restdocs/operation/Operation.java | 0 .../restdocs/operation/OperationRequest.java | 0 .../operation/OperationRequestPart.java | 0 .../restdocs/operation/OperationResponse.java | 0 .../restdocs/operation/Parameters.java | 0 .../restdocs/operation/StandardOperation.java | 0 .../operation/StandardOperationRequest.java | 0 .../StandardOperationRequestPart.java | 0 .../operation/StandardOperationResponse.java | 0 .../operation/preprocess/ContentModifier.java | 0 ...ContentModifyingOperationPreprocessor.java | 0 ...elegatingOperationRequestPreprocessor.java | 0 ...legatingOperationResponsePreprocessor.java | 0 .../HeaderRemovingOperationPreprocessor.java | 0 .../LinkMaskingContentModifier.java | 0 .../preprocess/OperationPreprocessor.java | 0 .../OperationRequestPreprocessor.java | 0 .../OperationResponsePreprocessor.java | 38 ++++ .../PatternReplacingContentModifier.java | 0 .../operation/preprocess/Preprocessors.java | 0 .../PrettyPrintingContentModifier.java | 0 .../payload/AbstractFieldsSnippet.java | 0 .../restdocs/payload/ContentHandler.java | 0 .../restdocs/payload/FieldDescriptor.java | 0 .../payload/FieldDoesNotExistException.java | 0 .../payload/FieldTypeRequiredException.java | 0 .../restdocs/payload/JsonContentHandler.java | 18 +- .../restdocs/payload/JsonFieldPath.java | 0 .../restdocs/payload/JsonFieldProcessor.java | 0 .../restdocs/payload/JsonFieldType.java | 0 .../payload/JsonFieldTypeResolver.java | 0 .../payload/PayloadDocumentation.java | 0 .../payload/PayloadHandlingException.java | 36 ++-- .../payload/RequestFieldsSnippet.java | 0 .../payload/ResponseFieldsSnippet.java | 0 .../restdocs/payload/XmlContentHandler.java | 0 .../request/AbstractParametersSnippet.java | 0 .../restdocs/request/ParameterDescriptor.java | 0 .../request/PathParametersSnippet.java | 0 .../request/RequestDocumentation.java | 0 .../request/RequestParametersSnippet.java | 0 .../restdocs/snippet/AbstractDescriptor.java | 22 ++- .../restdocs/snippet/Attributes.java | 0 ...cumentationContextPlaceholderResolver.java | 21 +-- .../restdocs/snippet/Snippet.java | 0 .../restdocs/snippet/SnippetException.java | 0 .../snippet/StandardWriterResolver.java | 16 +- .../restdocs/snippet/TemplatedSnippet.java | 7 +- .../restdocs/snippet/WriterResolver.java | 6 +- .../StandardTemplateResourceResolver.java | 0 .../restdocs/templates/Template.java | 38 ++++ .../restdocs/templates/TemplateEngine.java | 0 .../templates/TemplateResourceResolver.java | 0 .../templates/mustache/MustacheTemplate.java | 0 .../mustache/MustacheTemplateEngine.java | 0 .../DefaultConstraintDescriptions.properties | 0 .../templates/default-curl-request.snippet | 0 .../templates/default-http-request.snippet | 0 .../templates/default-http-response.snippet | 0 .../restdocs/templates/default-links.snippet | 0 .../templates/default-path-parameters.snippet | 0 .../templates/default-request-fields.snippet | 0 .../default-request-parameters.snippet | 0 .../templates/default-response-fields.snippet | 0 .../ConstraintDescriptionsTests.java | 18 +- ...dleConstraintDescriptionResolverTests.java | 18 +- .../ValidatorConstraintResolverTests.java | 18 +- .../curl/CurlRequestSnippetTests.java | 80 +++++---- .../http/HttpRequestSnippetTests.java | 52 +++--- .../http/HttpResponseSnippetTests.java | 24 +-- .../ContentTypeLinkExtractorTests.java | 0 .../LinkExtractorsPayloadTests.java | 0 .../hypermedia/LinksSnippetTests.java | 33 ++-- ...ntModifyingOperationPreprocessorTests.java | 18 +- ...tingOperationRequestPreprocessorTests.java | 60 +++++++ ...ingOperationResponsePreprocessorTests.java | 61 +++++++ ...derRemovingOperationPreprocessorTests.java | 18 +- .../LinkMaskingContentModifierTests.java | 18 +- .../PatternReplacingContentModifierTests.java | 18 +- .../PrettyPrintingContentModifierTests.java | 0 .../restdocs/payload/JsonFieldPathTests.java | 0 .../payload/JsonFieldProcessorTests.java | 0 .../payload/JsonFieldTypeResolverTests.java | 0 .../payload/RequestFieldsSnippetTests.java | 49 ++++-- .../payload/ResponseFieldsSnippetTests.java | 45 +++-- .../request/PathParametersSnippetTests.java | 31 ++-- .../RequestParametersSnippetTests.java | 24 +-- ...tationContextPlaceholderResolverTests.java | 65 +++++++ .../snippet/StandardWriterResolverTests.java | 34 ++-- .../restdocs/test/ExpectedSnippet.java | 40 ++--- .../restdocs/test/OperationBuilder.java | 29 +++- .../restdocs/test/SnippetMatchers.java | 0 .../curl-request-with-title.snippet | 0 .../http-request-with-title.snippet | 0 .../http-response-with-title.snippet | 0 .../links-with-extra-column.snippet | 0 .../links-with-title.snippet | 0 .../path-parameters-with-extra-column.snippet | 0 .../path-parameters-with-title.snippet | 0 .../request-fields-with-extra-column.snippet | 0 .../request-fields-with-title.snippet | 0 ...quest-parameters-with-extra-column.snippet | 0 .../request-parameters-with-title.snippet | 0 .../response-fields-with-extra-column.snippet | 0 .../response-fields-with-title.snippet | 0 ...ultiple-fields-and-embedded-and-links.json | 0 .../multiple-fields-and-embedded.json | 0 .../multiple-fields-and-links.json | 0 .../field-payloads/multiple-fields.json | 0 .../resources/field-payloads/no-fields.json | 0 .../field-payloads/single-field.json | 0 .../atom/multiple-links-different-rels.json | 0 .../atom/multiple-links-same-rels.json | 0 .../link-payloads/atom/no-links.json | 0 .../link-payloads/atom/single-link.json | 0 .../link-payloads/atom/wrong-format.json | 0 .../hal/multiple-links-different-rels.json | 0 .../hal/multiple-links-same-rels.json | 0 .../resources/link-payloads/hal/no-links.json | 0 .../link-payloads/hal/single-link.json | 0 .../link-payloads/hal/wrong-format.json | 0 .../TestConstraintDescriptions.properties | 0 spring-restdocs-mockmvc/build.gradle | 14 ++ .../restdocs/mockmvc}/AbstractConfigurer.java | 2 +- .../mockmvc}/AbstractNestedConfigurer.java | 2 +- .../MockMvcOperationRequestFactory.java | 11 +- .../MockMvcOperationResponseFactory.java | 6 +- .../mockmvc/MockMvcRestDocumentation.java | 20 ++- .../restdocs/mockmvc}/NestedConfigurer.java | 6 +- .../RestDocumentationMockMvcConfigurer.java | 53 +++--- .../RestDocumentationRequestBuilders.java | 2 +- .../RestDocumentationResultHandler.java | 8 +- .../restdocs/mockmvc}/SnippetConfigurer.java | 7 +- .../restdocs/mockmvc}/UriConfigurer.java | 6 +- .../mockmvc}/util/IterableEnumeration.java | 2 +- .../MockMvcOperationRequestFactoryTests.java | 22 ++- ...kMvcRestDocumentationIntegrationTests.java | 46 ++--- .../RestDocumentationConfigurerTests.java | 49 +++--- ...RestDocumentationRequestBuildersTests.java | 21 +-- .../restdocs/mockmvc}/test/StubMvcResult.java | 8 +- .../mockmvc}/test/TestRequestBuilders.java | 8 +- .../restdocs/templates/curl-request.snippet | 0 spring-restdocs/build.gradle | 116 ------------- .../config/RestDocumentationContext.java | 73 -------- ...estDocumentationTestExecutionListener.java | 41 ----- .../OperationResponsePreprocessor.java | 22 --- .../payload/PayloadHandlingException.java | 20 --- .../snippet/DocumentationProperties.java | 52 ------ .../restdocs/templates/Template.java | 22 --- .../main/resources/META-INF/spring.factories | 1 - .../config/RestDocumentationContexts.java | 6 - ...tationContextPlaceholderResolverTests.java | 61 ------- 207 files changed, 1396 insertions(+), 1425 deletions(-) delete mode 100644 samples/rest-notes-spring-data-rest/build.gradle delete mode 100644 samples/rest-notes-spring-data-rest/gradle/wrapper/gradle-wrapper.jar delete mode 100644 samples/rest-notes-spring-data-rest/gradle/wrapper/gradle-wrapper.properties delete mode 100755 samples/rest-notes-spring-data-rest/gradlew delete mode 100644 samples/rest-notes-spring-data-rest/gradlew.bat delete mode 100644 samples/rest-notes-spring-hateoas/pom.xml rename {spring-restdocs => spring-restdocs-core}/.settings/org.eclipse.jdt.core.prefs (100%) rename {spring-restdocs => spring-restdocs-core}/.settings/org.eclipse.jdt.ui.prefs (100%) create mode 100644 spring-restdocs-core/build.gradle create mode 100644 spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentation.java create mode 100644 spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationContext.java rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/constraints/Constraint.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptionResolver.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptions.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/constraints/ConstraintResolver.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/constraints/ValidatorConstraintResolver.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/curl/CurlRequestSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/http/HttpRequestSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/http/HttpResponseSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/AbstractJsonLinkExtractor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/AtomLinkExtractor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractor.java (73%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/HalLinkExtractor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/Link.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/LinkDescriptor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/LinkExtractor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/Operation.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/OperationRequest.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/OperationRequestPart.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/OperationResponse.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/Parameters.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/StandardOperation.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/StandardOperationRequest.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/StandardOperationRequestPart.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/StandardOperationResponse.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifier.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifier.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/OperationPreprocessor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/OperationRequestPreprocessor.java (100%) create mode 100644 spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifier.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifier.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/ContentHandler.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/FieldDescriptor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/FieldDoesNotExistException.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/FieldTypeRequiredException.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java (80%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/JsonFieldPath.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/JsonFieldProcessor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/JsonFieldType.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java (100%) rename spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContextHolder.java => spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java (50%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/request/ParameterDescriptor.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/snippet/AbstractDescriptor.java (60%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/snippet/Attributes.java (100%) rename {spring-restdocs/src/main/java/org/springframework/restdocs/config => spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet}/RestDocumentationContextPlaceholderResolver.java (81%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/snippet/Snippet.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/snippet/SnippetException.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/snippet/StandardWriterResolver.java (85%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/snippet/TemplatedSnippet.java (86%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/snippet/WriterResolver.java (84%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/templates/StandardTemplateResourceResolver.java (100%) create mode 100644 spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/Template.java rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/templates/TemplateEngine.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/templates/TemplateResourceResolver.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplate.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplateEngine.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-curl-request.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-http-request.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-http-response.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-links.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-path-parameters.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-request-fields.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-request-parameters.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/main/resources/org/springframework/restdocs/templates/default-response-fields.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/constraints/ConstraintDescriptionsTests.java (87%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java (91%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/constraints/ValidatorConstraintResolverTests.java (86%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/curl/CurlRequestSnippetTests.java (80%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java (85%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/http/HttpResponseSnippetTests.java (86%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractorTests.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/hypermedia/LinkExtractorsPayloadTests.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java (90%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessorTests.java (82%) create mode 100644 spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessorTests.java create mode 100644 spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessorTests.java rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessorTests.java (78%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifierTests.java (86%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifierTests.java (58%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifierTests.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/payload/JsonFieldPathTests.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/payload/JsonFieldProcessorTests.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java (87%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java (87%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java (87%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java (87%) create mode 100644 spring-restdocs-core/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/snippet/StandardWriterResolverTests.java (65%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/test/ExpectedSnippet.java (77%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/test/OperationBuilder.java (86%) rename {spring-restdocs => spring-restdocs-core}/src/test/java/org/springframework/restdocs/test/SnippetMatchers.java (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/curl-request-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/http-request-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/http-response-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/links-with-extra-column.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/links-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/path-parameters-with-extra-column.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/path-parameters-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/request-fields-with-extra-column.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/request-fields-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/request-parameters-with-extra-column.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/request-parameters-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/response-fields-with-extra-column.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/custom-snippet-templates/response-fields-with-title.snippet (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/field-payloads/multiple-fields-and-embedded-and-links.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/field-payloads/multiple-fields-and-embedded.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/field-payloads/multiple-fields-and-links.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/field-payloads/multiple-fields.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/field-payloads/no-fields.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/field-payloads/single-field.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/atom/multiple-links-different-rels.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/atom/multiple-links-same-rels.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/atom/no-links.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/atom/single-link.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/atom/wrong-format.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/hal/multiple-links-different-rels.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/hal/multiple-links-same-rels.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/hal/no-links.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/hal/single-link.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/link-payloads/hal/wrong-format.json (100%) rename {spring-restdocs => spring-restdocs-core}/src/test/resources/org/springframework/restdocs/constraints/TestConstraintDescriptions.properties (100%) create mode 100644 spring-restdocs-mockmvc/build.gradle rename {spring-restdocs/src/main/java/org/springframework/restdocs/config => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/AbstractConfigurer.java (95%) rename {spring-restdocs/src/main/java/org/springframework/restdocs/config => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/AbstractNestedConfigurer.java (97%) rename {spring-restdocs/src/main/java/org/springframework/restdocs/operation => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/MockMvcOperationRequestFactory.java (91%) rename {spring-restdocs/src/main/java/org/springframework/restdocs/operation => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/MockMvcOperationResponseFactory.java (88%) rename spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentation.java => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java (90%) rename {spring-restdocs/src/main/java/org/springframework/restdocs/config => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/NestedConfigurer.java (86%) rename spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationMockMvcConfigurer.java (79%) rename {spring-restdocs/src/main/java/org/springframework/restdocs => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/RestDocumentationRequestBuilders.java (99%) rename {spring-restdocs/src/main/java/org/springframework/restdocs => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/RestDocumentationResultHandler.java (93%) rename {spring-restdocs/src/main/java/org/springframework/restdocs/config => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/SnippetConfigurer.java (93%) rename {spring-restdocs/src/main/java/org/springframework/restdocs/config => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/UriConfigurer.java (93%) rename {spring-restdocs/src/main/java/org/springframework/restdocs => spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc}/util/IterableEnumeration.java (97%) rename {spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia => spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc}/MockMvcOperationRequestFactoryTests.java (92%) rename spring-restdocs/src/test/java/org/springframework/restdocs/RestDocumentationIntegrationTests.java => spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java (90%) rename {spring-restdocs/src/test/java/org/springframework/restdocs/config => spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc}/RestDocumentationConfigurerTests.java (73%) rename {spring-restdocs/src/test/java/org/springframework/restdocs => spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc}/RestDocumentationRequestBuildersTests.java (80%) rename {spring-restdocs/src/test/java/org/springframework/restdocs => spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc}/test/StubMvcResult.java (95%) rename {spring-restdocs/src/test/java/org/springframework/restdocs => spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc}/test/TestRequestBuilders.java (79%) rename {spring-restdocs => spring-restdocs-mockmvc}/src/test/resources/custom-snippet-templates/org/springframework/restdocs/templates/curl-request.snippet (100%) delete mode 100644 spring-restdocs/build.gradle delete mode 100644 spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContext.java delete mode 100644 spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationTestExecutionListener.java delete mode 100644 spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java delete mode 100644 spring-restdocs/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java delete mode 100644 spring-restdocs/src/main/java/org/springframework/restdocs/snippet/DocumentationProperties.java delete mode 100644 spring-restdocs/src/main/java/org/springframework/restdocs/templates/Template.java delete mode 100644 spring-restdocs/src/main/resources/META-INF/spring.factories delete mode 100644 spring-restdocs/src/test/java/org/springframework/restdocs/config/RestDocumentationContexts.java delete mode 100644 spring-restdocs/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java diff --git a/build.gradle b/build.gradle index ee1baef9..d2fb8d36 100644 --- a/build.gradle +++ b/build.gradle @@ -11,9 +11,33 @@ buildscript { allprojects { group = 'org.springframework.restdocs' + repositories { + jcenter() + } } apply plugin: 'samples' +apply plugin: 'sonar-runner' + +sonarRunner { + sonarProperties { + property 'sonar.jacoco.reportPath', "${buildDir.name}/jacoco.exec" + property 'sonar.java.coveragePlugin', 'jacoco' + property 'sonar.links.ci', 'https://build.spring.io/browse/SRD' + property 'sonar.links.homepage', 'https://github.com/spring-projects/spring-restdocs' + property 'sonar.links.issue', 'https://github.com/spring-projects/spring-restdocs' + property 'sonar.links.scm', 'https://github.com/spring-projects/spring-restdocs' + } +} + +ext { + springVersion = '4.1.7.RELEASE' + javadocLinks = [ + 'http://docs.oracle.com/javase/8/docs/api/', + "http://docs.spring.io/spring-framework/docs/$springVersion/javadoc-api/", + 'https://docs.jboss.org/hibernate/stable/beanvalidation/api/' + ] as String[] +} subprojects { apply plugin: 'io.spring.dependency-management' @@ -22,10 +46,14 @@ subprojects { apply plugin: 'propdeps' apply plugin: 'propdeps-eclipse' apply plugin: 'propdeps-maven' + apply plugin: 'maven' + + sourceCompatibility = 1.7 + targetCompatibility = 1.7 dependencyManagement { imports { - mavenBom 'org.springframework:spring-framework-bom:4.1.7.RELEASE' + mavenBom "org.springframework:spring-framework-bom:$springVersion" } dependencies { dependency 'com.fasterxml.jackson.core:jackson-databind:2.4.6' @@ -41,10 +69,53 @@ subprojects { dependency 'org.jacoco:org.jacoco.agent:0.7.2.201409121644' } } + + configurations { + jacoco + } + + dependencies { + jacoco 'org.jacoco:org.jacoco.agent::runtime' + } + + test { + testLogging { + exceptionFormat "full" + } + } + + javadoc { + description = "Generates project-level javadoc for use in -javadoc jar" + options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED + options.author = true + options.header = "Spring REST Docs $version" + options.docTitle = "${options.header} API" + options.links = javadocLinks + options.addStringOption '-quiet' + } + + eclipseJdt.onlyIf { false } + cleanEclipseJdt.onlyIf { false } + + task sourcesJar(type: Jar) { + classifier = 'sources' + from project.sourceSets.main.allSource + } + + task javadocJar(type: Jar) { + classifier = "javadoc" + from javadoc + } + + artifacts { + archives sourcesJar + archives javadocJar + } } samples { - dependOn 'spring-restdocs:install' + dependOn 'spring-restdocs-core:install' + dependOn 'spring-restdocs-mockmvc:install' restNotesSpringHateoas { workingDir 'samples/rest-notes-spring-hateoas' @@ -55,18 +126,44 @@ samples { } } -task docsZip(type: Zip, dependsOn: [':docs:asciidoctor', ':spring-restdocs:javadoc']) { +task api (type: Javadoc) { + group = "Documentation" + description = "Generates aggregated Javadoc API documentation." + dependsOn { + subprojects.collect { + it.tasks.getByName("jar") + } + } + options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED + options.author = true + options.header = "Spring REST Docs $version" + options.splitIndex = true + options.links = javadocLinks + options.addStringOption '-quiet' + + source subprojects.collect { project -> + project.sourceSets.main.allJava + } + + destinationDir = new File(buildDir, "api") + + doFirst { + classpath = files(subprojects.collect { it.sourceSets.main.compileClasspath }) + } +} + +task docsZip(type: Zip, dependsOn: [':docs:asciidoctor', ':api']) { group = 'Distribution' baseName = 'spring-restdocs' classifier = 'docs' - description = 'Builds -${classifier} archive containing API and reference documentation' + description = "Builds -${classifier} archive containing API and reference documentation" destinationDir = file("${project.buildDir}/distributions") - from (project.tasks.findByPath(':docs:asciidoctor')) { + from(project.tasks.findByPath(':docs:asciidoctor')) { into 'reference' } - from (project.tasks.findByPath(':spring-restdocs:javadoc')) { + from(api) { into 'api' } } diff --git a/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy b/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy index 7bf9293f..7551ecf2 100644 --- a/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy +++ b/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy @@ -37,14 +37,19 @@ public class SampleBuildConfigurer { } Task createTask(Project project, Object... dependencies) { - Task mavenBuild = mavenBuild(project, dependencies) - Task gradleBuild = gradleBuild(project, dependencies) Task verifyIncludes = verifyIncludes(project) - verifyIncludes.dependsOn mavenBuild, gradleBuild + if (new File(this.workingDir, 'build.gradle').isFile()) { + Task gradleBuild = gradleBuild(project, dependencies) + verifyIncludes.dependsOn gradleBuild + } + if (new File(this.workingDir, 'pom.xml').isFile()) { + Task mavenBuild = mavenBuild(project, dependencies) + verifyIncludes.dependsOn(mavenBuild) + } Task sampleBuild = project.tasks.create name sampleBuild.description = "Builds the ${name} sample" sampleBuild.group = "Build" - sampleBuild.dependsOn mavenBuild, gradleBuild, verifyIncludes + sampleBuild.dependsOn verifyIncludes return sampleBuild } diff --git a/docs/build.gradle b/docs/build.gradle index b3184452..5241018c 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -3,12 +3,8 @@ plugins { } dependencies { - compile 'org.springframework:spring-webmvc' - - testCompile project(':spring-restdocs') + testCompile project(':spring-restdocs-mockmvc') testCompile 'javax.validation:validation-api' - testCompile 'junit:junit' - testCompile 'org.springframework:spring-test' } tasks.findByPath("artifactoryPublish")?.enabled = false diff --git a/docs/src/docs/asciidoc/configuration.adoc b/docs/src/docs/asciidoc/configuration.adoc index e7a0a375..acd0fd2f 100644 --- a/docs/src/docs/asciidoc/configuration.adoc +++ b/docs/src/docs/asciidoc/configuration.adoc @@ -64,24 +64,4 @@ by default: [source,java,indent=0] ---- include::{examples-dir}/com/example/CustomDefaultSnippetsConfiguration.java[tags=custom-default-snippets] ----- - - - -[[configuration-output-directory]] -=== Snippet output directory - -As described in <> the snippet output directory is -configured in your `pom.xml` or `build.gradle` file. This configuration applies to builds -on the command line, but it may not apply when running your tests in your IDE. In the -absence of the property, Spring REST Docs will write the generated snippets to standard -out. - -If you'd prefer that your IDE writes the snippets to disk you can use a file in -`src/test/resources` named `documentation.properties` to specify the output directory that -should be used: - -[source,properties] ----- -org.springframework.restdocs.outputDir: target/generated-snippets ---- \ No newline at end of file diff --git a/docs/src/docs/asciidoc/getting-started.adoc b/docs/src/docs/asciidoc/getting-started.adoc index f07f9da6..c013ce47 100644 --- a/docs/src/docs/asciidoc/getting-started.adoc +++ b/docs/src/docs/asciidoc/getting-started.adoc @@ -36,10 +36,9 @@ The first step in using Spring REST Docs is to configure your project's build. [[getting-started-build-configuration-gradle]] ==== Gradle build configuration -Both {samples}[sample applications] contain `build.gradle` files that you may wish to -use as a reference. The key parts of the configuration are described below. - - +The {samples/rest-notes-spring-hateoas}[Spring HATEOAS sample] contains a `build.gradle` +file that you may wish to use as a reference. The key parts of the configuration are +described below. [source,groovy,indent=0,subs="verbatim,attributes"] ---- @@ -48,7 +47,7 @@ use as a reference. The key parts of the configuration are described below. } dependencies { <2> - testCompile 'org.springframework.restdocs:spring-restdocs:{project-version}' + testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:{project-version}' } ext { <3> @@ -56,24 +55,25 @@ use as a reference. The key parts of the configuration are described below. } test { <4> - systemProperty 'org.springframework.restdocs.outputDir', snippetsDir outputs.dir snippetsDir } asciidoctor { <5> - attributes 'snippets': snippetsDir - inputs.dir snippetsDir - dependsOn test + attributes 'snippets': snippetsDir <6> + inputs.dir snippetsDir <7> + dependsOn test <8> } ---- <1> Apply the Asciidoctor plugin. <2> Add a dependency on spring-restdocs in the `testCompile` configuration. <3> Configure a property to define the output location for generated snippets. -<4> Configure the `test` task with the `org.springframework.restdocs.outputDir` system -property. This property controls the location into which Spring REST Docs will write the -snippets that it generates. -<5> Configure the `asciidoctor` task and define an attribute named `snippets`. You can -then use this attribute when including the generated snippets in your documentation. +<4> Configure the `test` task to add the snippets directory as an output. +<5> Configure the `asciidoctor` task +<6> Define an attribute named `snippets` that can be used when including the generated + snippets in your documentation. +<7> Configure the snippets directory as an input. +<8> Make the task depend on the test task so that the tests are run before the + documentation is created. [[getting-started-build-configuration-gradle-packaging-the-documentation]] @@ -100,16 +100,15 @@ directory: [[getting-started-build-configuration-maven]] ==== Maven build configuration -Both {samples}[sample applications] contain `pom.xml` files that you may wish to -use as a reference. The key parts of the configuration are described below. - - +The {samples/rest-notes-spring-data-rest}[Spring Data REST sample] contains a `pom.xml` +file that you may wish to use as a reference. The key parts of the configuration are +described below. [source,xml,indent=0,subs="verbatim,attributes"] ---- <1> org.springframework.restdocs - spring-restdocs + spring-restdocs-mockmvc {project-version} test @@ -127,11 +126,6 @@ use as a reference. The key parts of the configuration are described below. **/*Documentation.java - - - ${snippetsDirectory} - - <4> @@ -159,14 +153,12 @@ use as a reference. The key parts of the configuration are described below. ---- -<1> Add a dependency on `spring-restdocs` in the `test` scope. +<1> Add a dependency on `spring-restdocs-mockmvc` in the `test` scope. <2> Configure a property to define the output location for generated snippets. -<3> Configure the SureFire plugin with the `org.springframework.restdocs.outputDir` system -property. This property controls the location into which Spring REST Docs will write the -snippets that it generates. The plugin is also configured to include files whose names end -with `Documentation.java`. -<4> Configure the Asciidoctor plugin and define an attribute named `snippets`. You can -then use this attribute when including the generated snippets in your documentation. +<3> Add the SureFire plugin and configure it to include files whose names end with + `Documentation.java`. +<4> Add the Asciidoctor plugin and configure it to define an attribute named `snippets` + that can be used when including the generated snippets in your documentation. <5> [[getting-started-build-configuration-maven-plugin-phase]] If you want to <> in your project's jar you should use the `prepare-package` phase. @@ -233,7 +225,8 @@ documentation snippets for the result's request and response. [[getting-started-documentation-snippets-setup]] ==== Setting up Spring MVC test -The first step in generating documentation snippets is to provide an `@Before` method +The first step in generating documentation snippets is to declare a `public` +`RestDocumentation` that's annotated as a JUnit `@Rule` and to provide an `@Before` method that creates a `MockMvc` instance: [source,java,indent=0] @@ -241,6 +234,10 @@ that creates a `MockMvc` instance: include::{examples-dir}/com/example/ExampleApplicationTests.java[tags=mock-mvc-setup] ---- +The `RestDocumentation` rule is configured with the output directory into which +generated snippets should be written. This output directory should match the snippets +directory that you have configured in your `build.gradle` or `pom.xml` file. + The `MockMvc` instance is configured using a `RestDocumentationConfigurer`. An instance of this class can be obtained from the static `documentationConfiguration()` method on `org.springframework.restdocs.RestDocumentation`. `RestDocumentationConfigurer` applies @@ -259,13 +256,14 @@ service and document the request and response. ---- include::{examples-dir}/com/example/InvokeService.java[tags=invoke-service] ---- -<1> Invoke the root (`/`) of the service an indicate that an `application/json` response +<1> Invoke the root (`/`) of the service and indicate that an `application/json` response is required. -<2> Assert that the service is produced the expected response. +<2> Assert that the service produced the expected response. <3> Document the call to the service, writing the snippets into a directory named `index` that will be located beneath the configured output directory. The snippets are written by a `RestDocumentationResultHandler`. An instance of this class can be obtained from the -static `document` method on `org.springframework.restdocs.RestDocumentation`. +static `document` method on +`org.springframework.restdocs.mockmvc.MockMvcRestDocumentation`. By default, three snippets a written: diff --git a/docs/src/test/java/com/example/AlwaysDo.java b/docs/src/test/java/com/example/AlwaysDo.java index d4575b9a..efc64f6c 100644 --- a/docs/src/test/java/com/example/AlwaysDo.java +++ b/docs/src/test/java/com/example/AlwaysDo.java @@ -16,25 +16,32 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; import org.junit.Before; +import org.junit.Rule; +import org.springframework.restdocs.RestDocumentation; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; public class AlwaysDo { + + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("build"); private MockMvc mockMvc; private WebApplicationContext context; + + // tag::always-do[] @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration()) + .apply(documentationConfiguration(this.restDocumentation)) .alwaysDo(document("{method-name}/{step}/")) .build(); } diff --git a/docs/src/test/java/com/example/Constraints.java b/docs/src/test/java/com/example/Constraints.java index 6370b30c..5bcea859 100644 --- a/docs/src/test/java/com/example/Constraints.java +++ b/docs/src/test/java/com/example/Constraints.java @@ -1,3 +1,19 @@ +/* + * 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 com.example; import java.util.List; @@ -15,17 +31,17 @@ public class Constraints { ConstraintDescriptions userConstraints = new ConstraintDescriptions(UserInput.class); // <1> List descriptions = userConstraints.descriptionsForProperty("name"); // <2> } - + static class UserInput { - + @NotNull @Size(min = 1) String name; - + @NotNull @Size(min = 8) String password; } // end::constraints[] - + } diff --git a/docs/src/test/java/com/example/CustomDefaultSnippetsConfiguration.java b/docs/src/test/java/com/example/CustomDefaultSnippetsConfiguration.java index 0a74af66..a964c964 100644 --- a/docs/src/test/java/com/example/CustomDefaultSnippetsConfiguration.java +++ b/docs/src/test/java/com/example/CustomDefaultSnippetsConfiguration.java @@ -1,16 +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 com.example; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; import static org.springframework.restdocs.curl.CurlDocumentation.curlRequest; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; import org.junit.Before; +import org.junit.Rule; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.restdocs.RestDocumentation; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; public class CustomDefaultSnippetsConfiguration { + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("build"); + @Autowired private WebApplicationContext context; @@ -20,7 +41,7 @@ public class CustomDefaultSnippetsConfiguration { public void setUp() { // tag::custom-default-snippets[] this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration().snippets() + .apply(documentationConfiguration(this.restDocumentation).snippets() .withDefaults(curlRequest())) .build(); // end::custom-default-snippets[] diff --git a/docs/src/test/java/com/example/CustomEncoding.java b/docs/src/test/java/com/example/CustomEncoding.java index 1c72fcff..4490e8a4 100644 --- a/docs/src/test/java/com/example/CustomEncoding.java +++ b/docs/src/test/java/com/example/CustomEncoding.java @@ -16,15 +16,20 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; import org.junit.Before; +import org.junit.Rule; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.restdocs.RestDocumentation; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; public class CustomEncoding { + + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("build"); @Autowired private WebApplicationContext context; @@ -35,7 +40,7 @@ public class CustomEncoding { public void setUp() { // tag::custom-encoding[] this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration().snippets() + .apply(documentationConfiguration(this.restDocumentation).snippets() .withEncoding("ISO-8859-1")) .build(); // end::custom-encoding[] diff --git a/docs/src/test/java/com/example/CustomUriConfiguration.java b/docs/src/test/java/com/example/CustomUriConfiguration.java index 038d5354..b70d4e08 100644 --- a/docs/src/test/java/com/example/CustomUriConfiguration.java +++ b/docs/src/test/java/com/example/CustomUriConfiguration.java @@ -16,15 +16,20 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; import org.junit.Before; +import org.junit.Rule; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.restdocs.RestDocumentation; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; public class CustomUriConfiguration { + + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("build"); @Autowired private WebApplicationContext context; @@ -35,7 +40,7 @@ public class CustomUriConfiguration { public void setUp() { // tag::custom-uri-configuration[] this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration().uris() + .apply(documentationConfiguration(this.restDocumentation).uris() .withScheme("https") .withHost("example.com") .withPort(443)) diff --git a/docs/src/test/java/com/example/ExampleApplicationTests.java b/docs/src/test/java/com/example/ExampleApplicationTests.java index e6c97e44..cc6c6406 100644 --- a/docs/src/test/java/com/example/ExampleApplicationTests.java +++ b/docs/src/test/java/com/example/ExampleApplicationTests.java @@ -17,16 +17,21 @@ package com.example; import org.junit.Before; +import org.junit.Rule; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.restdocs.RestDocumentation; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; public class ExampleApplicationTests { - + // tag::mock-mvc-setup[] + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("build/generated-snippets"); + @Autowired private WebApplicationContext context; @@ -35,7 +40,7 @@ public class ExampleApplicationTests { @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration()) + .apply(documentationConfiguration(this.restDocumentation)) .build(); } // end::mock-mvc-setup[] diff --git a/docs/src/test/java/com/example/Hypermedia.java b/docs/src/test/java/com/example/Hypermedia.java index 103529ea..3cf6c1bc 100644 --- a/docs/src/test/java/com/example/Hypermedia.java +++ b/docs/src/test/java/com/example/Hypermedia.java @@ -16,12 +16,12 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.halLinks; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; diff --git a/docs/src/test/java/com/example/InvokeService.java b/docs/src/test/java/com/example/InvokeService.java index 32fdaf65..097899f2 100644 --- a/docs/src/test/java/com/example/InvokeService.java +++ b/docs/src/test/java/com/example/InvokeService.java @@ -16,8 +16,8 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.http.MediaType; diff --git a/docs/src/test/java/com/example/PathParameters.java b/docs/src/test/java/com/example/PathParameters.java index 1754947e..c7810598 100644 --- a/docs/src/test/java/com/example/PathParameters.java +++ b/docs/src/test/java/com/example/PathParameters.java @@ -16,8 +16,8 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; diff --git a/docs/src/test/java/com/example/Payload.java b/docs/src/test/java/com/example/Payload.java index 132568a2..5ee1a890 100644 --- a/docs/src/test/java/com/example/Payload.java +++ b/docs/src/test/java/com/example/Payload.java @@ -16,9 +16,9 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; diff --git a/docs/src/test/java/com/example/Preprocessing.java b/docs/src/test/java/com/example/Preprocessing.java index cf2d9ad2..dbb83713 100644 --- a/docs/src/test/java/com/example/Preprocessing.java +++ b/docs/src/test/java/com/example/Preprocessing.java @@ -16,13 +16,13 @@ package com.example; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.RestDocumentation.document; import org.springframework.test.web.servlet.MockMvc; diff --git a/docs/src/test/java/com/example/RequestParameters.java b/docs/src/test/java/com/example/RequestParameters.java index 9155a5b9..5a314958 100644 --- a/docs/src/test/java/com/example/RequestParameters.java +++ b/docs/src/test/java/com/example/RequestParameters.java @@ -16,9 +16,9 @@ package com.example; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; diff --git a/samples/rest-notes-spring-data-rest/build.gradle b/samples/rest-notes-spring-data-rest/build.gradle deleted file mode 100644 index b30c212b..00000000 --- a/samples/rest-notes-spring-data-rest/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE' - } -} - -plugins { - id "org.asciidoctor.convert" version "1.5.2" -} - -apply plugin: 'java' -apply plugin: 'spring-boot' -apply plugin: 'eclipse' - -repositories { - mavenLocal() - maven { url 'https://repo.spring.io/snapshot' } - mavenCentral() -} - -group = 'com.example' - -sourceCompatibility = 1.7 -targetCompatibility = 1.7 - -dependencies { - compile 'org.springframework.boot:spring-boot-starter-data-rest' - compile 'org.springframework.boot:spring-boot-starter-data-jpa' - - runtime 'com.h2database:h2' - - testCompile 'com.jayway.jsonpath:json-path' - testCompile 'org.springframework.boot:spring-boot-starter-test' - testCompile 'org.springframework.restdocs:spring-restdocs:1.0.0.BUILD-SNAPSHOT' -} - -ext { - snippetsDir = file('build/generated-snippets') -} - -test { - systemProperty 'org.springframework.restdocs.outputDir', snippetsDir - outputs.dir snippetsDir -} - -asciidoctor { - sourceDir 'src/main/asciidoc' // Align with Maven's default location - attributes 'snippets': snippetsDir - inputs.dir snippetsDir - dependsOn test -} - -jar { - dependsOn asciidoctor - from ("${asciidoctor.outputDir}/html5") { - into 'static/docs' - } -} - -task wrapper(type: Wrapper) { - gradleVersion = '2.3' -} - -eclipseJdt.onlyIf { false } -cleanEclipseJdt.onlyIf { false } \ No newline at end of file diff --git a/samples/rest-notes-spring-data-rest/gradle/wrapper/gradle-wrapper.jar b/samples/rest-notes-spring-data-rest/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 3d0dee6e8edfecc92e04653ec780de06f7b34f8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51017 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 H-~Rf4?cF@p diff --git a/samples/rest-notes-spring-data-rest/gradle/wrapper/gradle-wrapper.properties b/samples/rest-notes-spring-data-rest/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 72d2eb27..00000000 --- a/samples/rest-notes-spring-data-rest/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Thu Apr 16 12:33:42 BST 2015 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-bin.zip diff --git a/samples/rest-notes-spring-data-rest/gradlew b/samples/rest-notes-spring-data-rest/gradlew deleted file mode 100755 index 91a7e269..00000000 --- a/samples/rest-notes-spring-data-rest/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/samples/rest-notes-spring-data-rest/gradlew.bat b/samples/rest-notes-spring-data-rest/gradlew.bat deleted file mode 100644 index 8a0b282a..00000000 --- a/samples/rest-notes-spring-data-rest/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/samples/rest-notes-spring-data-rest/pom.xml b/samples/rest-notes-spring-data-rest/pom.xml index b553763a..7e668af4 100644 --- a/samples/rest-notes-spring-data-rest/pom.xml +++ b/samples/rest-notes-spring-data-rest/pom.xml @@ -18,7 +18,6 @@ UTF-8 1.7 - ${project.build.directory}/generated-snippets @@ -49,7 +48,7 @@ org.springframework.restdocs - spring-restdocs + spring-restdocs-mockmvc 1.0.0.BUILD-SNAPSHOT test @@ -68,9 +67,6 @@ **/*Documentation.java - - ${snippetsDirectory} - @@ -88,7 +84,7 @@ html book - ${snippetsDirectory} + ${project.build.directory}/generated-snippets @@ -96,7 +92,6 @@ maven-resources-plugin - 2.7 copy-resources diff --git a/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/ApiDocumentation.java b/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/ApiDocumentation.java index cfa00bde..51581811 100644 --- a/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/ApiDocumentation.java +++ b/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/ApiDocumentation.java @@ -18,16 +18,16 @@ package com.example.notes; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.RestDocumentation.document; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.patch; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -39,11 +39,13 @@ import java.util.Map; import javax.servlet.RequestDispatcher; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.hateoas.MediaTypes; +import org.springframework.restdocs.RestDocumentation; import org.springframework.restdocs.payload.JsonFieldType; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -57,6 +59,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; @SpringApplicationConfiguration(classes = RestNotesSpringDataRest.class) @WebAppConfiguration public class ApiDocumentation { + + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets"); @Autowired private NoteRepository noteRepository; @@ -75,18 +80,7 @@ public class ApiDocumentation { @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration()).build(); - this.mockMvc = MockMvcBuilders - .webAppContextSetup(this.context) - .apply(documentationConfiguration() - .uris() - .withScheme("https") - .withHost("localhost") - .withPort(8443) - .and().snippets() - .withEncoding("ISO-8859-1")) - .build(); - + .apply(documentationConfiguration(this.restDocumentation)).build(); } @Test diff --git a/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/GettingStartedDocumentation.java b/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/GettingStartedDocumentation.java index a6afc59f..3770023b 100644 --- a/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/GettingStartedDocumentation.java +++ b/samples/rest-notes-spring-data-rest/src/test/java/com/example/notes/GettingStartedDocumentation.java @@ -19,11 +19,11 @@ package com.example.notes; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.patch; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -34,11 +34,13 @@ import java.util.HashMap; import java.util.Map; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.hateoas.MediaTypes; +import org.springframework.restdocs.RestDocumentation; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; @@ -54,6 +56,9 @@ import com.jayway.jsonpath.JsonPath; @SpringApplicationConfiguration(classes = RestNotesSpringDataRest.class) @WebAppConfiguration public class GettingStartedDocumentation { + + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets"); @Autowired private ObjectMapper objectMapper; @@ -66,7 +71,7 @@ public class GettingStartedDocumentation { @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration()) + .apply(documentationConfiguration(this.restDocumentation)) .alwaysDo(document("{method-name}/{step}/")) .build(); } diff --git a/samples/rest-notes-spring-hateoas/build.gradle b/samples/rest-notes-spring-hateoas/build.gradle index 5a2e164d..a8041b90 100644 --- a/samples/rest-notes-spring-hateoas/build.gradle +++ b/samples/rest-notes-spring-hateoas/build.gradle @@ -35,7 +35,7 @@ dependencies { testCompile 'com.jayway.jsonpath:json-path' testCompile 'org.springframework.boot:spring-boot-starter-test' - testCompile 'org.springframework.restdocs:spring-restdocs:1.0.0.BUILD-SNAPSHOT' + testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:1.0.0.BUILD-SNAPSHOT' } ext { @@ -43,7 +43,6 @@ ext { } test { - systemProperty 'org.springframework.restdocs.outputDir', snippetsDir outputs.dir snippetsDir } @@ -61,9 +60,5 @@ jar { } } -task wrapper(type: Wrapper) { - gradleVersion = '2.3' -} - eclipseJdt.onlyIf { false } cleanEclipseJdt.onlyIf { false } \ No newline at end of file diff --git a/samples/rest-notes-spring-hateoas/pom.xml b/samples/rest-notes-spring-hateoas/pom.xml deleted file mode 100644 index a9a1a339..00000000 --- a/samples/rest-notes-spring-hateoas/pom.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - 4.0.0 - - com.example - rest-notes-spring-hateoas - 0.0.1-SNAPSHOT - jar - - - org.springframework.boot - spring-boot-starter-parent - 1.2.5.RELEASE - - - - - UTF-8 - 1.7 - ${project.build.directory}/generated-snippets - - - - - org.springframework.boot - spring-boot-starter-hateoas - - - org.springframework.boot - spring-boot-starter-data-jpa - - - com.h2database - h2 - runtime - - - org.atteo - evo-inflector - 1.2 - runtime - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.jayway.jsonpath - json-path - test - - - org.springframework.restdocs - spring-restdocs - 1.0.0.BUILD-SNAPSHOT - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*Documentation.java - - - ${snippetsDirectory} - - - - - org.asciidoctor - asciidoctor-maven-plugin - 1.5.2 - - - generate-docs - prepare-package - - process-asciidoc - - - html - book - - ${snippetsDirectory} - - - - - - - maven-resources-plugin - 2.7 - - - copy-resources - prepare-package - - copy-resources - - - ${project.build.outputDirectory}/static/docs - - - ${project.build.directory}/generated-docs - - - - - - - - - - - - spring-snapshots - Spring snapshots - https://repo.spring.io/snapshot - - true - - - - - \ No newline at end of file diff --git a/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java b/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java index 06e22615..8a0978df 100644 --- a/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java +++ b/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java @@ -18,11 +18,11 @@ package com.example.notes; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.patch; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; @@ -40,11 +40,13 @@ import java.util.Map; import javax.servlet.RequestDispatcher; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.hateoas.MediaTypes; +import org.springframework.restdocs.RestDocumentation; import org.springframework.restdocs.constraints.ConstraintDescriptions; import org.springframework.restdocs.payload.FieldDescriptor; import org.springframework.restdocs.payload.JsonFieldType; @@ -61,6 +63,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; @SpringApplicationConfiguration(classes = RestNotesSpringHateoas.class) @WebAppConfiguration public class ApiDocumentation { + + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("build/generated-snippets"); @Autowired private NoteRepository noteRepository; @@ -79,7 +84,7 @@ public class ApiDocumentation { @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration()).build(); + .apply(documentationConfiguration(this.restDocumentation)).build(); } @Test diff --git a/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/GettingStartedDocumentation.java b/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/GettingStartedDocumentation.java index 79b78051..b1365729 100644 --- a/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/GettingStartedDocumentation.java +++ b/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/GettingStartedDocumentation.java @@ -19,11 +19,11 @@ package com.example.notes; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.springframework.restdocs.RestDocumentation.document; -import static org.springframework.restdocs.RestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.patch; -import static org.springframework.restdocs.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -34,11 +34,13 @@ import java.util.HashMap; import java.util.Map; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.hateoas.MediaTypes; +import org.springframework.restdocs.RestDocumentation; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; @@ -54,6 +56,9 @@ import com.jayway.jsonpath.JsonPath; @SpringApplicationConfiguration(classes = RestNotesSpringHateoas.class) @WebAppConfiguration public class GettingStartedDocumentation { + + @Rule + public final RestDocumentation restDocumentation = new RestDocumentation("build/generated-snippets"); @Autowired private ObjectMapper objectMapper; @@ -66,7 +71,7 @@ public class GettingStartedDocumentation { @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration()) + .apply(documentationConfiguration(this.restDocumentation)) .alwaysDo(document("{method-name}/{step}/")) .build(); } diff --git a/settings.gradle b/settings.gradle index ad08f6b3..7552e239 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ -rootProject.name = 'spring-restdocs-build' +rootProject.name = 'spring-restdocs' include 'docs' -include 'spring-restdocs' \ No newline at end of file +include 'spring-restdocs-core' +include 'spring-restdocs-mockmvc' \ No newline at end of file diff --git a/spring-restdocs/.settings/org.eclipse.jdt.core.prefs b/spring-restdocs-core/.settings/org.eclipse.jdt.core.prefs similarity index 100% rename from spring-restdocs/.settings/org.eclipse.jdt.core.prefs rename to spring-restdocs-core/.settings/org.eclipse.jdt.core.prefs diff --git a/spring-restdocs/.settings/org.eclipse.jdt.ui.prefs b/spring-restdocs-core/.settings/org.eclipse.jdt.ui.prefs similarity index 100% rename from spring-restdocs/.settings/org.eclipse.jdt.ui.prefs rename to spring-restdocs-core/.settings/org.eclipse.jdt.ui.prefs diff --git a/spring-restdocs-core/build.gradle b/spring-restdocs-core/build.gradle new file mode 100644 index 00000000..5f5be34f --- /dev/null +++ b/spring-restdocs-core/build.gradle @@ -0,0 +1,59 @@ +configurations { + jarjar + jmustache + testArtifacts.extendsFrom testRuntime +} + +task jmustacheRepackJar(type: Jar) { repackJar -> + repackJar.baseName = "restdocs-jmustache-repack" + repackJar.version = dependencyManagement.managedVersions['com.samskivert:jmustache'] + + doLast() { + project.ant { + taskdef name: "jarjar", classname: "com.tonicsystems.jarjar.JarJarTask", + classpath: configurations.jarjar.asPath + jarjar(destfile: repackJar.archivePath) { + configurations.jmustache.each { originalJar -> + zipfileset(src: originalJar, includes: '**/*.class') + } + rule(pattern: 'com.samskivert.**', result: 'org.springframework.restdocs.@1') + } + } + } +} + +dependencies { + compile 'com.fasterxml.jackson.core:jackson-databind' + compile 'junit:junit' + compile 'org.springframework:spring-webmvc' + compile 'javax.servlet:javax.servlet-api' + compile files(jmustacheRepackJar) + jarjar 'com.googlecode.jarjar:jarjar:1.3' + jmustache 'com.samskivert:jmustache@jar' + optional 'javax.validation:validation-api' + testCompile 'org.mockito:mockito-core' + testCompile 'org.hamcrest:hamcrest-core' + testCompile 'org.hamcrest:hamcrest-library' + testCompile 'org.hibernate:hibernate-validator' + testRuntime 'org.glassfish:javax.el:3.0.0' +} + +jar { + dependsOn jmustacheRepackJar + from(zipTree(jmustacheRepackJar.archivePath)) { + include "org/springframework/restdocs/**" + } +} + +task testJar(type: Jar) { + classifier "test" + from sourceSets.test.output +} + +artifacts { + testArtifacts testJar +} + +test { + jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=org.springframework.restdocs.*,excludes=org.springframework.restdocs.mustache.*" +} \ No newline at end of file diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentation.java new file mode 100644 index 00000000..fc72501e --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentation.java @@ -0,0 +1,81 @@ +/* + * 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; + +import java.io.File; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * A JUnit {@link TestRule} used to bootstrap the generation of REST documentation from + * JUnit tests. + * + * @author Andy Wilkinson + * + */ +public class RestDocumentation implements TestRule { + + private final String outputDirectory; + + private RestDocumentationContext context; + + /** + * Creates a new {@code RestDocumentation} instance that will generate snippets to the + * given {@code outputDirectory} + * + * @param outputDirectory the output directory + */ + public RestDocumentation(String outputDirectory) { + this.outputDirectory = outputDirectory; + } + + @Override + public Statement apply(final Statement base, final Description description) { + return new Statement() { + + @Override + public void evaluate() throws Throwable { + Class testClass = description.getTestClass(); + String methodName = description.getMethodName(); + RestDocumentation.this.context = new RestDocumentationContext(testClass, + methodName, new File(RestDocumentation.this.outputDirectory)); + try { + base.evaluate(); + } + finally { + RestDocumentation.this.context = null; + } + } + + }; + + } + + /** + * Notification that a RESTful operation that should be documented is about to be + * performed. Returns a {@link RestDocumentationContext} for the operation. + * + * @return the context for the operation + */ + public RestDocumentationContext beforeOperation() { + this.context.getAndIncrementStepCount(); + return this.context; + } + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationContext.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationContext.java new file mode 100644 index 00000000..cad0c71e --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationContext.java @@ -0,0 +1,99 @@ +/* + * 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; + +import java.io.File; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * {@code RestDocumentationContext} encapsulates the context in which the documentation of + * a RESTful API is being performed. + * + * @author Andy Wilkinson + */ +public final class RestDocumentationContext { + + private final AtomicInteger stepCount = new AtomicInteger(0); + + private final Class testClass; + + private final String testMethodName; + + private final File outputDirectory; + + /** + * Creates a new {@code RestDocumentationContext} for a test on the given + * {@code testClass} with given {@code testMethodName} that will generate + * documentation to the given {@code outputDirectory}. + * + * @param testClass the class whose test is being executed + * @param testMethodName the name of the test method that is being executed + * @param outputDirectory the directory to which documentation should be written. + */ + public RestDocumentationContext(Class testClass, String testMethodName, + File outputDirectory) { + this.testClass = testClass; + this.testMethodName = testMethodName; + this.outputDirectory = outputDirectory; + } + + /** + * Returns the class whose tests are currently executing + * + * @return The test class + */ + public Class getTestClass() { + return this.testClass; + } + + /** + * Returns the name of the test method that is currently executing + * + * @return The name of the test method + */ + public String getTestMethodName() { + return this.testMethodName; + } + + /** + * Returns the current step count and then increments it + * + * @return The step count prior to it being incremented + */ + int getAndIncrementStepCount() { + return this.stepCount.getAndIncrement(); + } + + /** + * Returns the current step count + * + * @return The current step count + */ + public int getStepCount() { + return this.stepCount.get(); + } + + /** + * Returns the output directory to which generated snippets should be written. + * + * @return the output directory + */ + public File getOutputDirectory() { + return this.outputDirectory; + } + +} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/constraints/Constraint.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/Constraint.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/constraints/Constraint.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/Constraint.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptionResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptionResolver.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptionResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptionResolver.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptions.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptions.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptions.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ConstraintDescriptions.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ConstraintResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ConstraintResolver.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ConstraintResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ConstraintResolver.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolver.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ValidatorConstraintResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ValidatorConstraintResolver.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/constraints/ValidatorConstraintResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/constraints/ValidatorConstraintResolver.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlRequestSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/curl/CurlRequestSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlRequestSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/curl/CurlRequestSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/http/HttpRequestSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpRequestSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/http/HttpRequestSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpRequestSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/http/HttpResponseSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpResponseSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/http/HttpResponseSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpResponseSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/AbstractJsonLinkExtractor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/AbstractJsonLinkExtractor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/AbstractJsonLinkExtractor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/AbstractJsonLinkExtractor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/AtomLinkExtractor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/AtomLinkExtractor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/AtomLinkExtractor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/AtomLinkExtractor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractor.java similarity index 73% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractor.java index 1c31ad3a..ec36eb63 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractor.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractor.java @@ -1,3 +1,19 @@ +/* + * 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 java.io.IOException; @@ -12,7 +28,7 @@ import org.springframework.restdocs.operation.OperationResponse; /** * {@link LinkExtractor} that delegates to other link extractors based on the response's * content type. - * + * * @author Andy Wilkinson * */ diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/HalLinkExtractor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HalLinkExtractor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/HalLinkExtractor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HalLinkExtractor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/Link.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/Link.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/Link.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/Link.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/LinkDescriptor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinkDescriptor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/LinkDescriptor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinkDescriptor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/LinkExtractor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinkExtractor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/LinkExtractor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinkExtractor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/Operation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/Operation.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/Operation.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/Operation.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/OperationRequest.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequest.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/OperationRequest.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequest.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/OperationRequestPart.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequestPart.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/OperationRequestPart.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequestPart.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/OperationResponse.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationResponse.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/OperationResponse.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationResponse.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/Parameters.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/Parameters.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/Parameters.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/Parameters.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperation.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperation.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperation.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperationRequest.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperationRequest.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperationRequest.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperationRequest.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperationRequestPart.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperationRequestPart.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperationRequestPart.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperationRequestPart.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperationResponse.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperationResponse.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/StandardOperationResponse.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/StandardOperationResponse.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifier.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifier.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifier.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifier.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifier.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifier.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifier.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifier.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationPreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationPreprocessor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationPreprocessor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationPreprocessor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationRequestPreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationRequestPreprocessor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationRequestPreprocessor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationRequestPreprocessor.java diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java new file mode 100644 index 00000000..4763b05b --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java @@ -0,0 +1,38 @@ +/* + * 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.operation.preprocess; + +import org.springframework.restdocs.operation.OperationResponse; + +/** + * An {@code OperationRequestPreprocessor} is used to modify an {@code OperationRequest} + * prior to it being documented. + * + * @author Andy Wilkinson + */ +public interface OperationResponsePreprocessor { + + /** + * Processes and potentially modifies the given {@code response} before it is + * documented. + * + * @param response the response + * @return the modified response + */ + OperationResponse preprocess(OperationResponse response); + +} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifier.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifier.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifier.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifier.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifier.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifier.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifier.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifier.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/ContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/ContentHandler.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/FieldDescriptor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldDescriptor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/FieldDescriptor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldDescriptor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/FieldDoesNotExistException.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldDoesNotExistException.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/FieldDoesNotExistException.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldDoesNotExistException.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/FieldTypeRequiredException.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeRequiredException.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/FieldTypeRequiredException.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeRequiredException.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java similarity index 80% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java index 2fe9e897..e20b4f8d 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java @@ -1,3 +1,19 @@ +/* + * 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.payload; import java.io.IOException; @@ -11,7 +27,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; /** * A {@link ContentHandler} for JSON content - * + * * @author Andy Wilkinson */ class JsonContentHandler implements ContentHandler { diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldPath.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldPath.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldPath.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldPath.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldProcessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldProcessor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldProcessor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldProcessor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldType.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldType.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldType.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldType.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContextHolder.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java similarity index 50% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContextHolder.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java index cefb3fbb..10362718 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContextHolder.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java @@ -14,29 +14,23 @@ * limitations under the License. */ -package org.springframework.restdocs.config; +package org.springframework.restdocs.payload; -import org.springframework.core.NamedInheritableThreadLocal; +/** + * Thrown to indicate that a failure has occurred during payload handling + * + * @author Andy Wilkinson + * + */ +@SuppressWarnings("serial") +class PayloadHandlingException extends RuntimeException { -final class RestDocumentationContextHolder { - - private static final NamedInheritableThreadLocal 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(); + /** + * Creates a new {@code PayloadHandlingException} with the given cause + * @param cause the cause of the failure + */ + PayloadHandlingException(Throwable cause) { + super(cause); } } diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/request/ParameterDescriptor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/ParameterDescriptor.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/request/ParameterDescriptor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/request/ParameterDescriptor.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/AbstractDescriptor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/AbstractDescriptor.java similarity index 60% rename from spring-restdocs/src/main/java/org/springframework/restdocs/snippet/AbstractDescriptor.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/AbstractDescriptor.java index d217b002..4766a171 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/AbstractDescriptor.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/AbstractDescriptor.java @@ -1,3 +1,19 @@ +/* + * 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.HashMap; @@ -8,7 +24,7 @@ import org.springframework.restdocs.snippet.Attributes.Attribute; /** * Base class for descriptors. Provides the ability to associate arbitrary attributes with * a descriptor. - * + * * @author Andy Wilkinson * * @param the type of the descriptor @@ -19,7 +35,7 @@ public abstract class AbstractDescriptor> { /** * Sets the descriptor's attributes - * + * * @param attributes the attributes * @return the descriptor */ @@ -33,7 +49,7 @@ public abstract class AbstractDescriptor> { /** * Returns the descriptor's attributes - * + * * @return the attributes */ protected Map getAttributes() { diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/Attributes.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/Attributes.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/snippet/Attributes.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/Attributes.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContextPlaceholderResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolver.java similarity index 81% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContextPlaceholderResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolver.java index 6a9645cd..706078d0 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContextPlaceholderResolver.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolver.java @@ -14,11 +14,12 @@ * limitations under the License. */ -package org.springframework.restdocs.config; +package org.springframework.restdocs.snippet; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.springframework.restdocs.RestDocumentationContext; import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; /** @@ -28,14 +29,14 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; *
  • {@code step} – the {@link RestDocumentationContext#getStepCount() step current * count}. *
  • {@code methodName} - the name of the - * {@link RestDocumentationContext#getTestMethod() current test method} formatted using - * camelCase + * {@link RestDocumentationContext#getTestMethodName() current test method} formatted + * using camelCase *
  • {@code method-name} - the name of the - * {@link RestDocumentationContext#getTestMethod() current test method} formatted using - * kebab-case + * {@link RestDocumentationContext#getTestMethodName() current test method} formatted + * using kebab-case *
  • {@code method_name} - the name of the - * {@link RestDocumentationContext#getTestMethod() current test method} formatted using - * snake_case + * {@link RestDocumentationContext#getTestMethodName() current test method} formatted + * using snake_case * * * @author Andy Wilkinson @@ -62,13 +63,13 @@ public class RestDocumentationContextPlaceholderResolver implements PlaceholderR return Integer.toString(this.context.getStepCount()); } if ("methodName".equals(placeholderName)) { - return this.context.getTestMethod().getName(); + return this.context.getTestMethodName(); } if ("method-name".equals(placeholderName)) { - return camelCaseToDash(this.context.getTestMethod().getName()); + return camelCaseToDash(this.context.getTestMethodName()); } if ("method_name".equals(placeholderName)) { - return camelCaseToUnderscore(this.context.getTestMethod().getName()); + return camelCaseToUnderscore(this.context.getTestMethodName()); } return null; } diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/Snippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/Snippet.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/snippet/Snippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/Snippet.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/SnippetException.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/SnippetException.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/snippet/SnippetException.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/SnippetException.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/StandardWriterResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/StandardWriterResolver.java similarity index 85% rename from spring-restdocs/src/main/java/org/springframework/restdocs/snippet/StandardWriterResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/StandardWriterResolver.java index fd4a52a7..2ba5d366 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/StandardWriterResolver.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/StandardWriterResolver.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; +import org.springframework.restdocs.RestDocumentationContext; import org.springframework.util.PropertyPlaceholderHelper; import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; @@ -51,9 +52,10 @@ public class StandardWriterResolver implements WriterResolver { } @Override - public Writer resolve(String operationName, String snippetName) throws IOException { + public Writer resolve(String operationName, String snippetName, + RestDocumentationContext context) throws IOException { File outputFile = resolveFile(this.propertyPlaceholderHelper.replacePlaceholders( - operationName, this.placeholderResolver), snippetName + ".adoc"); + operationName, this.placeholderResolver), snippetName + ".adoc", context); if (outputFile != null) { createDirectoriesIfNecessary(outputFile); @@ -69,16 +71,18 @@ public class StandardWriterResolver implements WriterResolver { this.encoding = encoding; } - protected File resolveFile(String outputDirectory, String fileName) { + protected File resolveFile(String outputDirectory, String fileName, + RestDocumentationContext context) { File outputFile = new File(outputDirectory, fileName); if (!outputFile.isAbsolute()) { - outputFile = makeRelativeToConfiguredOutputDir(outputFile); + outputFile = makeRelativeToConfiguredOutputDir(outputFile, context); } return outputFile; } - private File makeRelativeToConfiguredOutputDir(File outputFile) { - File configuredOutputDir = new DocumentationProperties().getOutputDir(); + private File makeRelativeToConfiguredOutputDir(File outputFile, + RestDocumentationContext context) { + File configuredOutputDir = context.getOutputDirectory(); if (configuredOutputDir != null) { return new File(configuredOutputDir, outputFile.getPath()); } diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/TemplatedSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/TemplatedSnippet.java similarity index 86% rename from spring-restdocs/src/main/java/org/springframework/restdocs/snippet/TemplatedSnippet.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/TemplatedSnippet.java index 7fc188bc..4e0cf65d 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/TemplatedSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/TemplatedSnippet.java @@ -21,6 +21,7 @@ import java.io.Writer; import java.util.HashMap; import java.util.Map; +import org.springframework.restdocs.RestDocumentationContext; import org.springframework.restdocs.operation.Operation; import org.springframework.restdocs.templates.Template; import org.springframework.restdocs.templates.TemplateEngine; @@ -46,10 +47,12 @@ public abstract class TemplatedSnippet implements Snippet { @Override public void document(Operation operation) throws IOException { + RestDocumentationContext context = (RestDocumentationContext) operation + .getAttributes().get(RestDocumentationContext.class.getName()); WriterResolver writerResolver = (WriterResolver) operation.getAttributes().get( WriterResolver.class.getName()); - try (Writer writer = writerResolver - .resolve(operation.getName(), this.snippetName)) { + try (Writer writer = writerResolver.resolve(operation.getName(), + this.snippetName, context)) { Map model = createModel(operation); model.putAll(this.attributes); TemplateEngine templateEngine = (TemplateEngine) operation.getAttributes() diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/WriterResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/WriterResolver.java similarity index 84% rename from spring-restdocs/src/main/java/org/springframework/restdocs/snippet/WriterResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/WriterResolver.java index 45948fc5..9adca5ca 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/WriterResolver.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/snippet/WriterResolver.java @@ -19,6 +19,8 @@ package org.springframework.restdocs.snippet; import java.io.IOException; import java.io.Writer; +import org.springframework.restdocs.RestDocumentationContext; + /** * 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. @@ -32,10 +34,12 @@ public interface WriterResolver { * operation with the given name. * @param operationName the name of the operation that is being documented * @param snippetName the name of the snippet + * @param restDocumentationContext the current documentation context * @return the writer * @throws IOException if a writer cannot be resolved */ - Writer resolve(String operationName, String snippetName) throws IOException; + Writer resolve(String operationName, String snippetName, + RestDocumentationContext restDocumentationContext) throws IOException; /** * Configures the encoding that should be used by any writers produced by this diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/templates/StandardTemplateResourceResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/StandardTemplateResourceResolver.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/templates/StandardTemplateResourceResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/StandardTemplateResourceResolver.java diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/Template.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/Template.java new file mode 100644 index 00000000..7275c529 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/Template.java @@ -0,0 +1,38 @@ +/* + * 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.templates; + +import java.util.Map; + +/** + * A compiled {@code Template} that can be rendered to a {@link String}. + * + * @author Andy Wilkinson + * + */ +public interface Template { + + /** + * Renders the template to a {@link String} using the given {@code context} for + * variable/property resolution. + * + * @param context The context to use + * @return The rendered template + */ + String render(Map context); + +} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/templates/TemplateEngine.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/TemplateEngine.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/templates/TemplateEngine.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/TemplateEngine.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/templates/TemplateResourceResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/TemplateResourceResolver.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/templates/TemplateResourceResolver.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/TemplateResourceResolver.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplate.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplate.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplate.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplate.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplateEngine.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplateEngine.java similarity index 100% rename from spring-restdocs/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplateEngine.java rename to spring-restdocs-core/src/main/java/org/springframework/restdocs/templates/mustache/MustacheTemplateEngine.java diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/constraints/DefaultConstraintDescriptions.properties diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-curl-request.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-curl-request.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-curl-request.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-curl-request.snippet diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-http-request.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-http-request.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-http-request.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-http-request.snippet diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-http-response.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-http-response.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-http-response.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-http-response.snippet diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-links.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-links.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-links.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-links.snippet diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-path-parameters.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-path-parameters.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-path-parameters.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-path-parameters.snippet diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-request-fields.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-request-fields.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-request-fields.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-request-fields.snippet diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-request-parameters.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-request-parameters.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-request-parameters.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-request-parameters.snippet diff --git a/spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-response-fields.snippet b/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-response-fields.snippet similarity index 100% rename from spring-restdocs/src/main/resources/org/springframework/restdocs/templates/default-response-fields.snippet rename to spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/default-response-fields.snippet diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ConstraintDescriptionsTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ConstraintDescriptionsTests.java similarity index 87% rename from spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ConstraintDescriptionsTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ConstraintDescriptionsTests.java index 8aa88989..e69192e2 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ConstraintDescriptionsTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ConstraintDescriptionsTests.java @@ -1,3 +1,19 @@ +/* + * 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.constraints; import static org.hamcrest.Matchers.contains; @@ -25,7 +41,7 @@ import org.junit.Test; /** * Tests for {@link ConstraintDescriptions} - * + * * @author Andy Wilkinson */ public class ConstraintDescriptionsTests { diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java similarity index 91% rename from spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java index 03202540..efb0f235 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ResourceBundleConstraintDescriptionResolverTests.java @@ -1,3 +1,19 @@ +/* + * 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.constraints; import static org.hamcrest.CoreMatchers.equalTo; @@ -29,7 +45,7 @@ import org.junit.Test; /** * Tests for {@link ResourceBundleConstraintDescriptionResolver} - * + * * @author Andy Wilkinson */ public class ResourceBundleConstraintDescriptionResolverTests { diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ValidatorConstraintResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ValidatorConstraintResolverTests.java similarity index 86% rename from spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ValidatorConstraintResolverTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ValidatorConstraintResolverTests.java index 26ab45ca..e07abd7f 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/constraints/ValidatorConstraintResolverTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/constraints/ValidatorConstraintResolverTests.java @@ -1,3 +1,19 @@ +/* + * 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.constraints; import static org.hamcrest.CoreMatchers.is; @@ -29,7 +45,7 @@ import org.junit.Test; /** * Tests for {@link ValidatorConstraintResolver} - * + * * @author Andy Wilkinson */ public class ValidatorConstraintResolverTests { diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/curl/CurlRequestSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/curl/CurlRequestSnippetTests.java similarity index 80% rename from spring-restdocs/src/test/java/org/springframework/restdocs/curl/CurlRequestSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/curl/CurlRequestSnippetTests.java index 48a8a566..96d6927a 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/curl/CurlRequestSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/curl/CurlRequestSnippetTests.java @@ -31,7 +31,6 @@ import org.junit.rules.ExpectedException; import org.springframework.core.io.FileSystemResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; -import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.restdocs.templates.TemplateEngine; import org.springframework.restdocs.templates.TemplateResourceResolver; import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine; @@ -58,16 +57,18 @@ public class CurlRequestSnippetTests { public void getRequest() throws IOException { this.snippet.expectCurlRequest("get-request").withContents( codeBlock("bash").content("$ curl 'http://localhost/foo' -i")); - new CurlRequestSnippet().document(new OperationBuilder("get-request").request( - "http://localhost/foo").build()); + new CurlRequestSnippet().document(new OperationBuilder("get-request", + this.snippet.getOutputDirectory()).request("http://localhost/foo") + .build()); } @Test public void nonGetRequest() throws IOException { this.snippet.expectCurlRequest("non-get-request").withContents( codeBlock("bash").content("$ curl 'http://localhost/foo' -i -X POST")); - new CurlRequestSnippet().document(new OperationBuilder("non-get-request") - .request("http://localhost/foo").method("POST").build()); + new CurlRequestSnippet().document(new OperationBuilder("non-get-request", + this.snippet.getOutputDirectory()).request("http://localhost/foo") + .method("POST").build()); } @Test @@ -75,8 +76,9 @@ public class CurlRequestSnippetTests { this.snippet.expectCurlRequest("request-with-content").withContents( codeBlock("bash") .content("$ curl 'http://localhost/foo' -i -d 'content'")); - new CurlRequestSnippet().document(new OperationBuilder("request-with-content") - .request("http://localhost/foo").content("content").build()); + new CurlRequestSnippet().document(new OperationBuilder("request-with-content", + this.snippet.getOutputDirectory()).request("http://localhost/foo") + .content("content").build()); } @Test @@ -86,8 +88,8 @@ public class CurlRequestSnippetTests { codeBlock("bash").content( "$ curl 'http://localhost/foo?param=value' -i")); new CurlRequestSnippet().document(new OperationBuilder( - "request-with-query-string").request("http://localhost/foo?param=value") - .build()); + "request-with-query-string", this.snippet.getOutputDirectory()).request( + "http://localhost/foo?param=value").build()); } @Test @@ -95,9 +97,11 @@ public class CurlRequestSnippetTests { this.snippet.expectCurlRequest("post-request-with-one-parameter").withContents( codeBlock("bash").content( "$ curl 'http://localhost/foo' -i -X POST -d 'k1=v1'")); - new CurlRequestSnippet().document(new OperationBuilder( - "post-request-with-one-parameter").request("http://localhost/foo") - .method("POST").param("k1", "v1").build()); + new CurlRequestSnippet() + .document(new OperationBuilder("post-request-with-one-parameter", + this.snippet.getOutputDirectory()) + .request("http://localhost/foo").method("POST").param("k1", "v1") + .build()); } @Test @@ -108,7 +112,8 @@ public class CurlRequestSnippetTests { "$ curl 'http://localhost/foo' -i -X POST" + " -d 'k1=v1&k1=v1-bis&k2=v2'")); new CurlRequestSnippet().document(new OperationBuilder( - "post-request-with-multiple-parameters").request("http://localhost/foo") + "post-request-with-multiple-parameters", this.snippet + .getOutputDirectory()).request("http://localhost/foo") .method("POST").param("k1", "v1", "v1-bis").param("k2", "v2").build()); } @@ -120,9 +125,9 @@ public class CurlRequestSnippetTests { codeBlock("bash").content( "$ curl 'http://localhost/foo' -i -X POST -d 'k1=a%26b'")); new CurlRequestSnippet().document(new OperationBuilder( - "post-request-with-url-encoded-parameter") - .request("http://localhost/foo").method("POST").param("k1", "a&b") - .build()); + "post-request-with-url-encoded-parameter", this.snippet + .getOutputDirectory()).request("http://localhost/foo") + .method("POST").param("k1", "a&b").build()); } @Test @@ -131,8 +136,8 @@ public class CurlRequestSnippetTests { codeBlock("bash").content( "$ curl 'http://localhost/foo' -i -X PUT -d 'k1=v1'")); new CurlRequestSnippet().document(new OperationBuilder( - "put-request-with-one-parameter").request("http://localhost/foo") - .method("PUT").param("k1", "v1").build()); + "put-request-with-one-parameter", this.snippet.getOutputDirectory()) + .request("http://localhost/foo").method("PUT").param("k1", "v1").build()); } @Test @@ -142,10 +147,11 @@ public class CurlRequestSnippetTests { codeBlock("bash").content( "$ curl 'http://localhost/foo' -i -X PUT" + " -d 'k1=v1&k1=v1-bis&k2=v2'")); - new CurlRequestSnippet().document(new OperationBuilder( - "put-request-with-multiple-parameters").request("http://localhost/foo") - .method("PUT").param("k1", "v1").param("k1", "v1-bis").param("k2", "v2") - .build()); + new CurlRequestSnippet() + .document(new OperationBuilder("put-request-with-multiple-parameters", + this.snippet.getOutputDirectory()) + .request("http://localhost/foo").method("PUT").param("k1", "v1") + .param("k1", "v1-bis").param("k2", "v2").build()); } @Test @@ -155,7 +161,8 @@ public class CurlRequestSnippetTests { codeBlock("bash").content( "$ curl 'http://localhost/foo' -i -X PUT -d 'k1=a%26b'")); new CurlRequestSnippet().document(new OperationBuilder( - "put-request-with-url-encoded-parameter").request("http://localhost/foo") + "put-request-with-url-encoded-parameter", this.snippet + .getOutputDirectory()).request("http://localhost/foo") .method("PUT").param("k1", "a&b").build()); } @@ -165,8 +172,8 @@ public class CurlRequestSnippetTests { codeBlock("bash").content( "$ curl 'http://localhost/foo' -i" + " -H 'Content-Type: application/json' -H 'a: alpha'")); - new CurlRequestSnippet().document(new OperationBuilder("request-with-headers") - .request("http://localhost/foo") + new CurlRequestSnippet().document(new OperationBuilder("request-with-headers", + this.snippet.getOutputDirectory()).request("http://localhost/foo") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .header("a", "alpha").build()); } @@ -179,8 +186,8 @@ public class CurlRequestSnippetTests { this.snippet.expectCurlRequest("multipart-post-no-original-filename") .withContents(codeBlock("bash").content(expectedContent)); new CurlRequestSnippet().document(new OperationBuilder( - "multipart-post-no-original-filename").request("http://localhost/upload") - .method("POST") + "multipart-post-no-original-filename", this.snippet.getOutputDirectory()) + .request("http://localhost/upload").method("POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE) .part("metadata", "{\"description\": \"foo\"}".getBytes()).build()); } @@ -193,8 +200,8 @@ public class CurlRequestSnippetTests { this.snippet.expectCurlRequest("multipart-post-with-content-type").withContents( codeBlock("bash").content(expectedContent)); new CurlRequestSnippet().document(new OperationBuilder( - "multipart-post-with-content-type").request("http://localhost/upload") - .method("POST") + "multipart-post-with-content-type", this.snippet.getOutputDirectory()) + .request("http://localhost/upload").method("POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE) .part("image", new byte[0]) .header(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE) @@ -208,8 +215,9 @@ public class CurlRequestSnippetTests { + "'image=@documents/images/example.png'"; this.snippet.expectCurlRequest("multipart-post").withContents( codeBlock("bash").content(expectedContent)); - new CurlRequestSnippet().document(new OperationBuilder("multipart-post") - .request("http://localhost/upload").method("POST") + new CurlRequestSnippet().document(new OperationBuilder("multipart-post", + this.snippet.getOutputDirectory()).request("http://localhost/upload") + .method("POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE) .part("image", new byte[0]) .submittedFileName("documents/images/example.png").build()); @@ -224,8 +232,8 @@ public class CurlRequestSnippetTests { this.snippet.expectCurlRequest("multipart-post-with-parameters").withContents( codeBlock("bash").content(expectedContent)); new CurlRequestSnippet().document(new OperationBuilder( - "multipart-post-with-parameters").request("http://localhost/upload") - .method("POST") + "multipart-post-with-parameters", this.snippet.getOutputDirectory()) + .request("http://localhost/upload").method("POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE) .part("image", new byte[0]) .submittedFileName("documents/images/example.png").and() @@ -236,16 +244,14 @@ public class CurlRequestSnippetTests { public void customAttributes() throws IOException { this.snippet.expectCurlRequest("custom-attributes").withContents( containsString("curl request title")); - MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); TemplateResourceResolver resolver = mock(TemplateResourceResolver.class); when(resolver.resolveTemplateResource("curl-request")) .thenReturn( new FileSystemResource( "src/test/resources/custom-snippet-templates/curl-request-with-title.snippet")); - request.setAttribute(TemplateEngine.class.getName(), new MustacheTemplateEngine( - resolver)); new CurlRequestSnippet(attributes(key("title").value("curl request title"))) - .document(new OperationBuilder("custom-attributes") + .document(new OperationBuilder("custom-attributes", this.snippet + .getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)) .request("http://localhost/foo").build()); diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java similarity index 85% rename from spring-restdocs/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java index 3eacda6e..8da93faa 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java @@ -59,8 +59,9 @@ public class HttpRequestSnippetTests { httpRequest(GET, "/foo").header(HttpHeaders.HOST, "localhost").header( "Alpha", "a")); - new HttpRequestSnippet().document(new OperationBuilder("get-request") - .request("http://localhost/foo").header("Alpha", "a").build()); + new HttpRequestSnippet().document(new OperationBuilder("get-request", + this.snippet.getOutputDirectory()).request("http://localhost/foo") + .header("Alpha", "a").build()); } @Test @@ -69,8 +70,8 @@ public class HttpRequestSnippetTests { httpRequest(GET, "/foo?bar=baz").header(HttpHeaders.HOST, "localhost")); new HttpRequestSnippet().document(new OperationBuilder( - "get-request-with-query-string").request("http://localhost/foo?bar=baz") - .build()); + "get-request-with-query-string", this.snippet.getOutputDirectory()) + .request("http://localhost/foo?bar=baz").build()); } @Test @@ -80,8 +81,9 @@ public class HttpRequestSnippetTests { "Hello, world")); new HttpRequestSnippet().document(new OperationBuilder( - "post-request-with-content").request("http://localhost/foo") - .method("POST").content("Hello, world").build()); + "post-request-with-content", this.snippet.getOutputDirectory()) + .request("http://localhost/foo").method("POST").content("Hello, world") + .build()); } @Test @@ -92,8 +94,9 @@ public class HttpRequestSnippetTests { .content("b%26r=baz&a=alpha")); new HttpRequestSnippet().document(new OperationBuilder( - "post-request-with-parameter").request("http://localhost/foo") - .method("POST").param("b&r", "baz").param("a", "alpha").build()); + "post-request-with-parameter", this.snippet.getOutputDirectory()) + .request("http://localhost/foo").method("POST").param("b&r", "baz") + .param("a", "alpha").build()); } @Test @@ -102,10 +105,10 @@ public class HttpRequestSnippetTests { httpRequest(PUT, "/foo").header(HttpHeaders.HOST, "localhost").content( "Hello, world")); - new HttpRequestSnippet() - .document(new OperationBuilder("put-request-with-content") - .request("http://localhost/foo").method("PUT") - .content("Hello, world").build()); + new HttpRequestSnippet().document(new OperationBuilder( + "put-request-with-content", this.snippet.getOutputDirectory()) + .request("http://localhost/foo").method("PUT").content("Hello, world") + .build()); } @Test @@ -116,8 +119,9 @@ public class HttpRequestSnippetTests { .content("b%26r=baz&a=alpha")); new HttpRequestSnippet().document(new OperationBuilder( - "put-request-with-parameter").request("http://localhost/foo") - .method("PUT").param("b&r", "baz").param("a", "alpha").build()); + "put-request-with-parameter", this.snippet.getOutputDirectory()) + .request("http://localhost/foo").method("PUT").param("b&r", "baz") + .param("a", "alpha").build()); } @Test @@ -130,8 +134,9 @@ public class HttpRequestSnippetTests { .header("Content-Type", "multipart/form-data; boundary=" + BOUNDARY) .content(expectedContent)); - new HttpRequestSnippet().document(new OperationBuilder("multipart-post") - .request("http://localhost/upload").method("POST") + new HttpRequestSnippet().document(new OperationBuilder("multipart-post", + this.snippet.getOutputDirectory()).request("http://localhost/upload") + .method("POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE) .part("image", "<< data >>".getBytes()).build()); } @@ -154,8 +159,8 @@ public class HttpRequestSnippetTests { "multipart/form-data; boundary=" + BOUNDARY) .content(expectedContent)); new HttpRequestSnippet().document(new OperationBuilder( - "multipart-post-with-parameters").request("http://localhost/upload") - .method("POST") + "multipart-post-with-parameters", this.snippet.getOutputDirectory()) + .request("http://localhost/upload").method("POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE) .param("a", "apple", "avocado").param("b", "banana") .part("image", "<< data >>".getBytes()).build()); @@ -173,8 +178,8 @@ public class HttpRequestSnippetTests { "multipart/form-data; boundary=" + BOUNDARY) .content(expectedContent)); new HttpRequestSnippet().document(new OperationBuilder( - "multipart-post-with-content-type").request("http://localhost/upload") - .method("POST") + "multipart-post-with-content-type", this.snippet.getOutputDirectory()) + .request("http://localhost/upload").method("POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE) .part("image", "<< data >>".getBytes()) .header(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE).build()); @@ -184,8 +189,8 @@ public class HttpRequestSnippetTests { public void getRequestWithCustomHost() throws IOException { this.snippet.expectHttpRequest("get-request-custom-host").withContents( httpRequest(GET, "/foo").header(HttpHeaders.HOST, "api.example.com")); - new HttpRequestSnippet().document(new OperationBuilder("get-request-custom-host") - .request("http://localhost/foo") + new HttpRequestSnippet().document(new OperationBuilder("get-request-custom-host", + this.snippet.getOutputDirectory()).request("http://localhost/foo") .header(HttpHeaders.HOST, "api.example.com").build()); } @@ -199,7 +204,8 @@ public class HttpRequestSnippetTests { new FileSystemResource( "src/test/resources/custom-snippet-templates/http-request-with-title.snippet")); new HttpRequestSnippet(attributes(key("title").value("Title for the request"))) - .document(new OperationBuilder("request-with-snippet-attributes") + .document(new OperationBuilder("request-with-snippet-attributes", + this.snippet.getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)) .request("http://localhost/foo").build()); diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/http/HttpResponseSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/http/HttpResponseSnippetTests.java similarity index 86% rename from spring-restdocs/src/test/java/org/springframework/restdocs/http/HttpResponseSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/http/HttpResponseSnippetTests.java index 068d6b88..cfe68c60 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/http/HttpResponseSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/http/HttpResponseSnippetTests.java @@ -52,16 +52,17 @@ public class HttpResponseSnippetTests { @Test public void basicResponse() throws IOException { this.snippet.expectHttpResponse("basic-response").withContents(httpResponse(OK)); - new HttpResponseSnippet() - .document(new OperationBuilder("basic-response").build()); + new HttpResponseSnippet().document(new OperationBuilder("basic-response", + this.snippet.getOutputDirectory()).build()); } @Test public void nonOkResponse() throws IOException { this.snippet.expectHttpResponse("non-ok-response").withContents( httpResponse(BAD_REQUEST)); - new HttpResponseSnippet().document(new OperationBuilder("non-ok-response") - .response().status(BAD_REQUEST.value()).build()); + new HttpResponseSnippet().document(new OperationBuilder("non-ok-response", + this.snippet.getOutputDirectory()).response().status(BAD_REQUEST.value()) + .build()); } @Test @@ -70,8 +71,8 @@ public class HttpResponseSnippetTests { httpResponse(OK) // .header("Content-Type", "application/json") // .header("a", "alpha")); - new HttpResponseSnippet().document(new OperationBuilder("response-with-headers") - .response() + new HttpResponseSnippet().document(new OperationBuilder("response-with-headers", + this.snippet.getOutputDirectory()).response() .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .header("a", "alpha").build()); } @@ -80,8 +81,8 @@ public class HttpResponseSnippetTests { public void responseWithContent() throws IOException { this.snippet.expectHttpResponse("response-with-content").withContents( httpResponse(OK).content("content")); - new HttpResponseSnippet().document(new OperationBuilder("response-with-content") - .response().content("content").build()); + new HttpResponseSnippet().document(new OperationBuilder("response-with-content", + this.snippet.getOutputDirectory()).response().content("content").build()); } @Test @@ -94,9 +95,10 @@ public class HttpResponseSnippetTests { new FileSystemResource( "src/test/resources/custom-snippet-templates/http-response-with-title.snippet")); new HttpResponseSnippet(attributes(key("title").value("Title for the response"))) - .document(new OperationBuilder("response-with-snippet-attributes") - .attribute(TemplateEngine.class.getName(), - new MustacheTemplateEngine(resolver)).build()); + .document(new OperationBuilder("response-with-snippet-attributes", + this.snippet.getOutputDirectory()).attribute( + TemplateEngine.class.getName(), + new MustacheTemplateEngine(resolver)).build()); } } diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractorTests.java similarity index 100% rename from spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractorTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/ContentTypeLinkExtractorTests.java diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia/LinkExtractorsPayloadTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinkExtractorsPayloadTests.java similarity index 100% rename from spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia/LinkExtractorsPayloadTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinkExtractorsPayloadTests.java diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java similarity index 90% rename from spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java index 97979bdc..f5a51480 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java @@ -32,7 +32,6 @@ import org.junit.Rule; 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.operation.OperationResponse; import org.springframework.restdocs.snippet.SnippetException; import org.springframework.restdocs.templates.TemplateEngine; @@ -45,7 +44,7 @@ import org.springframework.util.MultiValueMap; /** * Tests for {@link LinksSnippet} - * + * * @author Andy Wilkinson */ public class LinksSnippetTests { @@ -63,7 +62,7 @@ public class LinksSnippetTests { + " documented: [foo]")); new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "bar")), Collections. emptyList()).document(new OperationBuilder( - "undocumented-link").build()); + "undocumented-link", this.snippet.getOutputDirectory()).build()); } @Test @@ -72,8 +71,8 @@ public class LinksSnippetTests { this.thrown.expectMessage(equalTo("Links with the following relations were not" + " found in the response: [foo]")); new LinksSnippet(new StubLinkExtractor(), Arrays.asList(new LinkDescriptor("foo") - .description("bar"))).document(new OperationBuilder("missing-link") - .build()); + .description("bar"))).document(new OperationBuilder("missing-link", + this.snippet.getOutputDirectory()).build()); } @Test @@ -83,7 +82,8 @@ public class LinksSnippetTests { .row("foo", "bar")); new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "blah")), Arrays.asList(new LinkDescriptor("foo").description("bar").optional())) - .document(new OperationBuilder("documented-optional-link").build()); + .document(new OperationBuilder("documented-optional-link", this.snippet + .getOutputDirectory()).build()); } @Test @@ -93,7 +93,7 @@ public class LinksSnippetTests { .row("foo", "bar")); new LinksSnippet(new StubLinkExtractor(), Arrays.asList(new LinkDescriptor("foo") .description("bar").optional())).document(new OperationBuilder( - "missing-optional-link").build()); + "missing-optional-link", this.snippet.getOutputDirectory()).build()); } @Test @@ -104,8 +104,8 @@ public class LinksSnippetTests { + " found in the response: [foo]")); new LinksSnippet(new StubLinkExtractor().withLinks(new Link("a", "alpha")), Arrays.asList(new LinkDescriptor("foo").description("bar"))) - .document(new OperationBuilder("undocumented-link-and-missing-link") - .build()); + .document(new OperationBuilder("undocumented-link-and-missing-link", + this.snippet.getOutputDirectory()).build()); } @Test @@ -118,7 +118,8 @@ public class LinksSnippetTests { new Link("b", "bravo")), Arrays.asList( new LinkDescriptor("a").description("one"), new LinkDescriptor("b").description("two"))) - .document(new OperationBuilder("documented-links").build()); + .document(new OperationBuilder("documented-links", this.snippet + .getOutputDirectory()).build()); } @Test @@ -127,23 +128,20 @@ public class LinksSnippetTests { tableWithHeader("Relation", "Description", "Foo") // .row("a", "one", "alpha") // .row("b", "two", "bravo")); - MockHttpServletRequest request = new MockHttpServletRequest(); TemplateResourceResolver resolver = mock(TemplateResourceResolver.class); when(resolver.resolveTemplateResource("links")) .thenReturn( new FileSystemResource( "src/test/resources/custom-snippet-templates/links-with-extra-column.snippet")); - request.setAttribute(TemplateEngine.class.getName(), new MustacheTemplateEngine( - resolver)); new LinksSnippet(new StubLinkExtractor().withLinks(new Link("a", "alpha"), new Link("b", "bravo")), Arrays.asList( new LinkDescriptor("a").description("one").attributes( key("foo").value("alpha")), new LinkDescriptor("b").description("two").attributes( key("foo").value("bravo")))).document(new OperationBuilder( - "links-with-custom-descriptor-attributes").attribute( - TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)) - .build()); + "links-with-custom-descriptor-attributes", this.snippet + .getOutputDirectory()).attribute(TemplateEngine.class.getName(), + new MustacheTemplateEngine(resolver)).build()); } @Test @@ -160,7 +158,8 @@ public class LinksSnippetTests { "Title for the links")), Arrays.asList( new LinkDescriptor("a").description("one"), new LinkDescriptor("b").description("two"))) - .document(new OperationBuilder("links-with-custom-attributes").attribute( + .document(new OperationBuilder("links-with-custom-attributes", + this.snippet.getOutputDirectory()).attribute( TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)).build()); } diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessorTests.java similarity index 82% rename from spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessorTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessorTests.java index 0a31fd8f..f13509b5 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessorTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/ContentModifyingOperationPreprocessorTests.java @@ -1,3 +1,19 @@ +/* + * 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.operation.preprocess; import static org.hamcrest.CoreMatchers.equalTo; @@ -20,7 +36,7 @@ import org.springframework.restdocs.operation.StandardOperationResponse; /** * Tests for {@link ContentModifyingOperationPreprocessor} - * + * * @author Andy Wilkinson * */ diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessorTests.java new file mode 100644 index 00000000..fdfe17c7 --- /dev/null +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationRequestPreprocessorTests.java @@ -0,0 +1,60 @@ +/* + * 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.operation.preprocess; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.restdocs.operation.OperationRequest; + +/** + * Tests for {@link DelegatingOperationRequestPreprocessor} + * + * @author Andy Wilkinson + */ +public class DelegatingOperationRequestPreprocessorTests { + + @Test + public void delegationOccurs() { + OperationRequest originalRequest = mock(OperationRequest.class); + + OperationPreprocessor preprocessor1 = mock(OperationPreprocessor.class); + OperationRequest preprocessedRequest1 = mock(OperationRequest.class); + when(preprocessor1.preprocess(originalRequest)).thenReturn(preprocessedRequest1); + + OperationPreprocessor preprocessor2 = mock(OperationPreprocessor.class); + OperationRequest preprocessedRequest2 = mock(OperationRequest.class); + when(preprocessor2.preprocess(preprocessedRequest1)).thenReturn( + preprocessedRequest2); + + OperationPreprocessor preprocessor3 = mock(OperationPreprocessor.class); + OperationRequest preprocessedRequest3 = mock(OperationRequest.class); + when(preprocessor3.preprocess(preprocessedRequest2)).thenReturn( + preprocessedRequest3); + + OperationRequest result = new DelegatingOperationRequestPreprocessor( + Arrays.asList(preprocessor1, preprocessor2, preprocessor3)) + .preprocess(originalRequest); + + assertThat(result, is(preprocessedRequest3)); + } +} diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessorTests.java new file mode 100644 index 00000000..764eb63d --- /dev/null +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/DelegatingOperationResponsePreprocessorTests.java @@ -0,0 +1,61 @@ +/* + * 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.operation.preprocess; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.restdocs.operation.OperationResponse; + +/** + * Tests for {@link DelegatingOperationResponsePreprocessor} + * + * @author Andy Wilkinson + */ +public class DelegatingOperationResponsePreprocessorTests { + + @Test + public void delegationOccurs() { + OperationResponse originalResponse = mock(OperationResponse.class); + + OperationPreprocessor preprocessor1 = mock(OperationPreprocessor.class); + OperationResponse preprocessedResponse1 = mock(OperationResponse.class); + when(preprocessor1.preprocess(originalResponse)) + .thenReturn(preprocessedResponse1); + + OperationPreprocessor preprocessor2 = mock(OperationPreprocessor.class); + OperationResponse preprocessedResponse2 = mock(OperationResponse.class); + when(preprocessor2.preprocess(preprocessedResponse1)).thenReturn( + preprocessedResponse2); + + OperationPreprocessor preprocessor3 = mock(OperationPreprocessor.class); + OperationResponse preprocessedResponse3 = mock(OperationResponse.class); + when(preprocessor3.preprocess(preprocessedResponse2)).thenReturn( + preprocessedResponse3); + + OperationResponse result = new DelegatingOperationResponsePreprocessor( + Arrays.asList(preprocessor1, preprocessor2, preprocessor3)) + .preprocess(originalResponse); + + assertThat(result, is(preprocessedResponse3)); + } +} diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessorTests.java similarity index 78% rename from spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessorTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessorTests.java index c90f4afd..cf710c81 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessorTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/HeaderRemovingOperationPreprocessorTests.java @@ -1,3 +1,19 @@ +/* + * 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.operation.preprocess; import static org.hamcrest.CoreMatchers.equalTo; @@ -22,7 +38,7 @@ import org.springframework.restdocs.operation.StandardOperationResponse; /** * Tests for {@link HeaderRemovingOperationPreprocessorTests} - * + * * @author Andy Wilkinson * */ diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifierTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifierTests.java similarity index 86% rename from spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifierTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifierTests.java index 2763d646..aa881ba8 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifierTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/LinkMaskingContentModifierTests.java @@ -1,3 +1,19 @@ +/* + * 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.operation.preprocess; import static org.hamcrest.CoreMatchers.equalTo; @@ -20,7 +36,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; /** * Tests for {@link LinkMaskingContentModifier} - * + * * @author Andy Wilkinson * */ diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifierTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifierTests.java similarity index 58% rename from spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifierTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifierTests.java index f419296d..c7a1e2c9 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifierTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/PatternReplacingContentModifierTests.java @@ -1,3 +1,19 @@ +/* + * 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.operation.preprocess; import static org.hamcrest.CoreMatchers.equalTo; @@ -10,7 +26,7 @@ import org.junit.Test; /** * Tests for {@link PatternReplacingContentModifier} - * + * * @author Andy Wilkinson * */ diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifierTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifierTests.java similarity index 100% rename from spring-restdocs/src/test/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifierTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/PrettyPrintingContentModifierTests.java diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/payload/JsonFieldPathTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldPathTests.java similarity index 100% rename from spring-restdocs/src/test/java/org/springframework/restdocs/payload/JsonFieldPathTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldPathTests.java diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/payload/JsonFieldProcessorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldProcessorTests.java similarity index 100% rename from spring-restdocs/src/test/java/org/springframework/restdocs/payload/JsonFieldProcessorTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldProcessorTests.java diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java similarity index 100% rename from spring-restdocs/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java similarity index 87% rename from spring-restdocs/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java index bec7ee7e..35168549 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java @@ -67,7 +67,8 @@ public class RequestFieldsSnippetTests { new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one"), fieldWithPath("a.c").description("two"), fieldWithPath("a").description("three"))).document(new OperationBuilder( - "map-request-with-fields").request("http://localhost") + "map-request-with-fields", this.snippet.getOutputDirectory()) + .request("http://localhost") .content("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}").build()); } @@ -82,7 +83,8 @@ public class RequestFieldsSnippetTests { new RequestFieldsSnippet(Arrays.asList(fieldWithPath("[]a.b").description("one"), fieldWithPath("[]a.c").description("two"), fieldWithPath("[]a") .description("three"))).document(new OperationBuilder( - "array-request-with-fields").request("http://localhost") + "array-request-with-fields", this.snippet.getOutputDirectory()) + .request("http://localhost") .content("[{\"a\": {\"b\": 5}},{\"a\": {\"c\": \"charlie\"}}]").build()); } @@ -93,8 +95,9 @@ public class RequestFieldsSnippetTests { .expectMessage(startsWith("The following parts of the payload were not" + " documented:")); new RequestFieldsSnippet(Collections. emptyList()) - .document(new OperationBuilder("undocumented-request-field") - .request("http://localhost").content("{\"a\": 5}").build()); + .document(new OperationBuilder("undocumented-request-field", this.snippet + .getOutputDirectory()).request("http://localhost") + .content("{\"a\": 5}").build()); } @Test @@ -104,8 +107,9 @@ public class RequestFieldsSnippetTests { .expectMessage(equalTo("Fields with the following paths were not found" + " in the payload: [a.b]")); new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one"))) - .document(new OperationBuilder("missing-request-fields") - .request("http://localhost").content("{}").build()); + .document(new OperationBuilder("missing-request-fields", this.snippet + .getOutputDirectory()).request("http://localhost").content("{}") + .build()); } @Test @@ -113,8 +117,9 @@ public class RequestFieldsSnippetTests { this.thrown.expect(FieldTypeRequiredException.class); new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one") .optional())).document(new OperationBuilder( - "missing-optional-request-field-with-no-type") - .request("http://localhost").content("{ }").build()); + "missing-optional-request-field-with-no-type", this.snippet + .getOutputDirectory()).request("http://localhost").content("{ }") + .build()); } @Test @@ -128,9 +133,9 @@ public class RequestFieldsSnippetTests { + " in the payload: [a.b]")); new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one"))) .document(new OperationBuilder( - "undocumented-request-field-and-missing-request-field") - .request("http://localhost").content("{ \"a\": { \"c\": 5 }}") - .build()); + "undocumented-request-field-and-missing-request-field", + this.snippet.getOutputDirectory()).request("http://localhost") + .content("{ \"a\": { \"c\": 5 }}").build()); } @Test @@ -151,7 +156,8 @@ public class RequestFieldsSnippetTests { key("foo").value("bravo")), fieldWithPath("a").description("three").attributes( key("foo").value("charlie")))).document(new OperationBuilder( - "request-fields-with-custom-descriptor-attributes") + "request-fields-with-custom-descriptor-attributes", this.snippet + .getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)).request("http://localhost") .content("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}").build()); @@ -166,7 +172,8 @@ public class RequestFieldsSnippetTests { snippetResource("request-fields-with-title")); new RequestFieldsSnippet(attributes(key("title").value("Custom title")), Arrays.asList(fieldWithPath("a").description("one"))) - .document(new OperationBuilder("request-fields-with-custom-attributes") + .document(new OperationBuilder("request-fields-with-custom-attributes", + this.snippet.getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)) .request("http://localhost").content("{\"a\": \"foo\"}").build()); @@ -183,7 +190,8 @@ public class RequestFieldsSnippetTests { new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one") .type("b"), fieldWithPath("a/c").description("two").type("c"), fieldWithPath("a").description("three").type("a"))) - .document(new OperationBuilder("xml-request") + .document(new OperationBuilder("xml-request", this.snippet + .getOutputDirectory()) .request("http://localhost") .content("5charlie") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) @@ -197,7 +205,8 @@ public class RequestFieldsSnippetTests { .expectMessage(startsWith("The following parts of the payload were not" + " documented:")); new RequestFieldsSnippet(Collections. emptyList()) - .document(new OperationBuilder("undocumented-xml-request-field") + .document(new OperationBuilder("undocumented-xml-request-field", + this.snippet.getOutputDirectory()) .request("http://localhost") .content("5") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) @@ -208,7 +217,8 @@ public class RequestFieldsSnippetTests { public void xmlRequestFieldWithNoType() throws IOException { this.thrown.expect(FieldTypeRequiredException.class); new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one"))) - .document(new OperationBuilder("missing-xml-request") + .document(new OperationBuilder("missing-xml-request", this.snippet + .getOutputDirectory()) .request("http://localhost") .content("5") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) @@ -223,8 +233,8 @@ public class RequestFieldsSnippetTests { + " in the payload: [a/b]")); new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one"), fieldWithPath("a").description("one"))).document(new OperationBuilder( - "missing-xml-request-fields").request("http://localhost") - .content("") + "missing-xml-request-fields", this.snippet.getOutputDirectory()) + .request("http://localhost").content("") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) .build()); } @@ -240,7 +250,8 @@ public class RequestFieldsSnippetTests { + " in the payload: [a/b]")); new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one"))) .document(new OperationBuilder( - "undocumented-xml-request-field-and-missing-xml-request-field") + "undocumented-xml-request-field-and-missing-xml-request-field", + this.snippet.getOutputDirectory()) .request("http://localhost") .content("5") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java similarity index 87% rename from spring-restdocs/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java index 9018f96d..16f5a853 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java @@ -35,7 +35,6 @@ import org.junit.rules.ExpectedException; import org.springframework.core.io.FileSystemResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; -import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.restdocs.snippet.SnippetException; import org.springframework.restdocs.templates.TemplateEngine; import org.springframework.restdocs.templates.TemplateResourceResolver; @@ -44,7 +43,7 @@ import org.springframework.restdocs.test.ExpectedSnippet; import org.springframework.restdocs.test.OperationBuilder; /** - * Tests for {@link PayloadDocumentation} + * Tests for {@link ReponseFieldsSnippet} * * @author Andy Wilkinson */ @@ -72,7 +71,8 @@ public class ResponseFieldsSnippetTests { fieldWithPath("assets[]").description("four"), fieldWithPath("assets[].id").description("five"), fieldWithPath("assets[].name").description("six"))) - .document(new OperationBuilder("map-response-with-fields") + .document(new OperationBuilder("map-response-with-fields", this.snippet + .getOutputDirectory()) .response() .content( "{\"id\": 67,\"date\": \"2015-01-20\",\"assets\":" @@ -90,7 +90,8 @@ public class ResponseFieldsSnippetTests { new ResponseFieldsSnippet(Arrays.asList( fieldWithPath("[]a.b").description("one"), fieldWithPath("[]a.c") .description("two"), fieldWithPath("[]a").description("three"))) - .document(new OperationBuilder("array-response-with-fields").response() + .document(new OperationBuilder("array-response-with-fields", this.snippet + .getOutputDirectory()).response() .content("[{\"a\": {\"b\": 5}},{\"a\": {\"c\": \"charlie\"}}]") .build()); } @@ -101,7 +102,8 @@ public class ResponseFieldsSnippetTests { tableWithHeader("Path", "Type", "Description") // .row("[]", "String", "one")); new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("[]").description("one"))) - .document(new OperationBuilder("array-response").response() + .document(new OperationBuilder("array-response", this.snippet + .getOutputDirectory()).response() .content("[\"a\", \"b\", \"c\"]").build()); } @@ -123,7 +125,8 @@ public class ResponseFieldsSnippetTests { key("foo").value("bravo")), fieldWithPath("a").description("three").attributes( key("foo").value("charlie")))).document(new OperationBuilder( - "response-fields-with-custom-attributes") + "response-fields-with-custom-attributes", this.snippet + .getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)).response() .content("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}").build()); @@ -138,7 +141,8 @@ public class ResponseFieldsSnippetTests { snippetResource("response-fields-with-title")); new ResponseFieldsSnippet(attributes(key("title").value("Custom title")), Arrays.asList(fieldWithPath("a").description("one"))) - .document(new OperationBuilder("response-fields-with-custom-attributes") + .document(new OperationBuilder("response-fields-with-custom-attributes", + this.snippet.getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)).response() .content("{\"a\": \"foo\"}").build()); @@ -154,7 +158,8 @@ public class ResponseFieldsSnippetTests { new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one") .type("b"), fieldWithPath("a/c").description("two").type("c"), fieldWithPath("a").description("three").type("a"))) - .document(new OperationBuilder("xml-response") + .document(new OperationBuilder("xml-response", this.snippet + .getOutputDirectory()) .response() .content("5charlie") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) @@ -167,11 +172,9 @@ public class ResponseFieldsSnippetTests { this.thrown .expectMessage(startsWith("The following parts of the payload were not" + " documented:")); - MockHttpServletResponse response = new MockHttpServletResponse(); - response.setContentType(MediaType.APPLICATION_XML_VALUE); - response.getOutputStream().print("5"); new ResponseFieldsSnippet(Collections. emptyList()) - .document(new OperationBuilder("undocumented-xml-response-field") + .document(new OperationBuilder("undocumented-xml-response-field", + this.snippet.getOutputDirectory()) .response() .content("5") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) @@ -181,11 +184,9 @@ public class ResponseFieldsSnippetTests { @Test public void xmlResponseFieldWithNoType() throws IOException { this.thrown.expect(FieldTypeRequiredException.class); - MockHttpServletResponse response = new MockHttpServletResponse(); - response.setContentType(MediaType.APPLICATION_XML_VALUE); - response.getOutputStream().print("5"); new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one"))) - .document(new OperationBuilder("xml-response-no-field-type") + .document(new OperationBuilder("xml-response-no-field-type", this.snippet + .getOutputDirectory()) .response() .content("5") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) @@ -198,12 +199,10 @@ public class ResponseFieldsSnippetTests { this.thrown .expectMessage(equalTo("Fields with the following paths were not found" + " in the payload: [a/b]")); - MockHttpServletResponse response = new MockHttpServletResponse(); - response.setContentType(MediaType.APPLICATION_XML_VALUE); - response.getOutputStream().print(""); new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one"), fieldWithPath("a").description("one"))).document(new OperationBuilder( - "missing-xml-response-field").response().content("") + "missing-xml-response-field", this.snippet.getOutputDirectory()) + .response().content("") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) .build()); } @@ -218,12 +217,10 @@ public class ResponseFieldsSnippetTests { this.thrown .expectMessage(endsWith("Fields with the following paths were not found" + " in the payload: [a/b]")); - MockHttpServletResponse response = new MockHttpServletResponse(); - response.setContentType(MediaType.APPLICATION_XML_VALUE); - response.getOutputStream().print("5"); new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one"))) .document(new OperationBuilder( - "undocumented-xml-request-field-and-missing-xml-request-field") + "undocumented-xml-request-field-and-missing-xml-request-field", + this.snippet.getOutputDirectory()) .response() .content("5") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java similarity index 87% rename from spring-restdocs/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java index c4204d8c..5c5657c8 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java @@ -61,7 +61,8 @@ public class PathParametersSnippetTests { this.thrown.expectMessage(equalTo("Path parameters with the following names were" + " not documented: [a]")); new PathParametersSnippet(Collections. emptyList()) - .document(new OperationBuilder("undocumented-path-parameter").attribute( + .document(new OperationBuilder("undocumented-path-parameter", + this.snippet.getOutputDirectory()).attribute( "org.springframework.restdocs.urlTemplate", "/{a}/").build()); } @@ -72,7 +73,8 @@ public class PathParametersSnippetTests { + " not found in the request: [a]")); new PathParametersSnippet( Arrays.asList(parameterWithName("a").description("one"))) - .document(new OperationBuilder("missing-path-parameter").attribute( + .document(new OperationBuilder("missing-path-parameter", this.snippet + .getOutputDirectory()).attribute( "org.springframework.restdocs.urlTemplate", "/").build()); } @@ -84,9 +86,10 @@ public class PathParametersSnippetTests { + " names were not found in the request: [a]")); new PathParametersSnippet( Arrays.asList(parameterWithName("a").description("one"))) - .document(new OperationBuilder("undocumented-and-missing-path-parameters") - .attribute("org.springframework.restdocs.urlTemplate", "/{b}") - .build()); + .document(new OperationBuilder( + "undocumented-and-missing-path-parameters", this.snippet + .getOutputDirectory()).attribute( + "org.springframework.restdocs.urlTemplate", "/{b}").build()); } @Test @@ -97,8 +100,8 @@ public class PathParametersSnippetTests { new PathParametersSnippet(Arrays.asList( parameterWithName("a").description("one"), parameterWithName("b") .description("two"))).document(new OperationBuilder( - "path-parameters").attribute("org.springframework.restdocs.urlTemplate", - "/{a}/{b}").build()); + "path-parameters", this.snippet.getOutputDirectory()).attribute( + "org.springframework.restdocs.urlTemplate", "/{a}/{b}").build()); } @Test @@ -109,9 +112,11 @@ public class PathParametersSnippetTests { .row("a", "one").row("b", "two")); new PathParametersSnippet(Arrays.asList( parameterWithName("a").description("one"), parameterWithName("b") - .description("two"))).document(new OperationBuilder( - "path-parameters-with-query-string").attribute( - "org.springframework.restdocs.urlTemplate", "/{a}/{b}?foo=bar").build()); + .description("two"))) + .document(new OperationBuilder("path-parameters-with-query-string", + this.snippet.getOutputDirectory()).attribute( + "org.springframework.restdocs.urlTemplate", "/{a}/{b}?foo=bar") + .build()); } @Test @@ -127,7 +132,8 @@ public class PathParametersSnippetTests { .attributes(key("foo").value("alpha")), parameterWithName("b") .description("two").attributes(key("foo").value("bravo")))) .document(new OperationBuilder( - "path-parameters-with-custom-descriptor-attributes") + "path-parameters-with-custom-descriptor-attributes", this.snippet + .getOutputDirectory()) .attribute("org.springframework.restdocs.urlTemplate", "/{a}/{b}") .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)).build()); @@ -146,7 +152,8 @@ public class PathParametersSnippetTests { parameterWithName("a").description("one").attributes( key("foo").value("alpha")), parameterWithName("b") .description("two").attributes(key("foo").value("bravo")))) - .document(new OperationBuilder("path-parameters-with-custom-attributes") + .document(new OperationBuilder("path-parameters-with-custom-attributes", + this.snippet.getOutputDirectory()) .attribute("org.springframework.restdocs.urlTemplate", "/{a}/{b}") .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)).build()); diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java similarity index 87% rename from spring-restdocs/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java index 0ec85773..5a071ffd 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java @@ -60,8 +60,9 @@ public class RequestParametersSnippetTests { .expectMessage(equalTo("Request parameters with the following names were" + " not documented: [a]")); new RequestParametersSnippet(Collections. emptyList()) - .document(new OperationBuilder("undocumented-parameter") - .request("http://localhost").param("a", "alpha").build()); + .document(new OperationBuilder("undocumented-parameter", this.snippet + .getOutputDirectory()).request("http://localhost") + .param("a", "alpha").build()); } @Test @@ -71,8 +72,8 @@ public class RequestParametersSnippetTests { .expectMessage(equalTo("Request parameters with the following names were" + " not found in the request: [a]")); new RequestParametersSnippet(Arrays.asList(parameterWithName("a").description( - "one"))).document(new OperationBuilder("missing-parameter").request( - "http://localhost").build()); + "one"))).document(new OperationBuilder("missing-parameter", this.snippet + .getOutputDirectory()).request("http://localhost").build()); } @Test @@ -84,8 +85,8 @@ public class RequestParametersSnippetTests { + " names were not found in the request: [a]")); new RequestParametersSnippet(Arrays.asList(parameterWithName("a").description( "one"))).document(new OperationBuilder( - "undocumented-and-missing-parameters").request("http://localhost") - .param("b", "bravo").build()); + "undocumented-and-missing-parameters", this.snippet.getOutputDirectory()) + .request("http://localhost").param("b", "bravo").build()); } @Test @@ -96,8 +97,9 @@ public class RequestParametersSnippetTests { new RequestParametersSnippet(Arrays.asList( parameterWithName("a").description("one"), parameterWithName("b") .description("two"))).document(new OperationBuilder( - "request-parameters").request("http://localhost").param("a", "bravo") - .param("b", "bravo").build()); + "request-parameters", this.snippet.getOutputDirectory()) + .request("http://localhost").param("a", "bravo").param("b", "bravo") + .build()); } @Test @@ -114,7 +116,8 @@ public class RequestParametersSnippetTests { key("foo").value("alpha")), parameterWithName("b").description("two").attributes( key("foo").value("bravo")))).document(new OperationBuilder( - "request-parameters-with-custom-descriptor-attributes") + "request-parameters-with-custom-descriptor-attributes", this.snippet + .getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)).request("http://localhost") .param("a", "alpha").param("b", "bravo").build()); @@ -134,7 +137,8 @@ public class RequestParametersSnippetTests { key("foo").value("alpha")), parameterWithName("b") .description("two").attributes(key("foo").value("bravo")))) .document(new OperationBuilder( - "request-parameters-with-custom-attributes") + "request-parameters-with-custom-attributes", this.snippet + .getOutputDirectory()) .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)) .request("http://localhost").param("a", "alpha") diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java new file mode 100644 index 00000000..ff06d8b3 --- /dev/null +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java @@ -0,0 +1,65 @@ +/* + * 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.equalTo; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.springframework.restdocs.RestDocumentationContext; +import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; + +/** + * Tests for {@link RestDocumentationContextPlaceholderResolver} + * + * @author Andy Wilkinson + * + */ +public class RestDocumentationContextPlaceholderResolverTests { + + @Test + public void dashSeparatedMethodName() throws Exception { + assertThat( + createResolver("dashSeparatedMethodName").resolvePlaceholder( + "method-name"), equalTo("dash-separated-method-name")); + } + + @Test + public void underscoreSeparatedMethodName() throws Exception { + assertThat( + createResolver("underscoreSeparatedMethodName").resolvePlaceholder( + "method_name"), equalTo("underscore_separated_method_name")); + } + + @Test + public void camelCaseMethodName() throws Exception { + assertThat( + createResolver("camelCaseMethodName").resolvePlaceholder("methodName"), + equalTo("camelCaseMethodName")); + } + + @Test + public void stepCount() throws Exception { + assertThat(createResolver("stepCount").resolvePlaceholder("step"), equalTo("0")); + } + + private PlaceholderResolver createResolver(String methodName) { + return new RestDocumentationContextPlaceholderResolver( + new RestDocumentationContext(null, methodName, null)); + } + +} diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/snippet/StandardWriterResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/snippet/StandardWriterResolverTests.java similarity index 65% rename from spring-restdocs/src/test/java/org/springframework/restdocs/snippet/StandardWriterResolverTests.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/snippet/StandardWriterResolverTests.java index c1882d27..2f186dd0 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/snippet/StandardWriterResolverTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/snippet/StandardWriterResolverTests.java @@ -24,7 +24,7 @@ import static org.mockito.Mockito.mock; import java.io.File; import org.junit.Test; -import org.springframework.restdocs.snippet.StandardWriterResolver; +import org.springframework.restdocs.RestDocumentationContext; import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; /** @@ -41,41 +41,33 @@ public class StandardWriterResolverTests { @Test public void noConfiguredOutputDirectoryAndRelativeInput() { - assertThat(this.resolver.resolveFile("foo", "bar.txt"), is(nullValue())); + assertThat(this.resolver.resolveFile("foo", "bar.txt", + new RestDocumentationContext(null, null, null)), is(nullValue())); } @Test public void absoluteInput() { String absolutePath = new File("foo").getAbsolutePath(); - assertThat(this.resolver.resolveFile(absolutePath, "bar.txt"), is(new File( + assertThat(this.resolver.resolveFile(absolutePath, "bar.txt", + new RestDocumentationContext(null, null, null)), 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"); - } + File outputDir = new File("foo").getAbsoluteFile(); + assertThat(this.resolver.resolveFile("bar", "baz.txt", + new RestDocumentationContext(null, null, outputDir)), is(new File( + outputDir, "bar/baz.txt"))); } @Test public void configuredOutputAndAbsoluteInput() { - String outputDir = new File("foo").getAbsolutePath(); + File outputDir = new File("foo").getAbsoluteFile(); 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"); - } + assertThat(this.resolver.resolveFile(absolutePath, "baz.txt", + new RestDocumentationContext(null, null, outputDir)), is(new File( + absolutePath, "baz.txt"))); } } diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/test/ExpectedSnippet.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/test/ExpectedSnippet.java similarity index 77% rename from spring-restdocs/src/test/java/org/springframework/restdocs/test/ExpectedSnippet.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/test/ExpectedSnippet.java index c3b72eb3..9786aa20 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/test/ExpectedSnippet.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/test/ExpectedSnippet.java @@ -43,37 +43,13 @@ public class ExpectedSnippet implements TestRule { private SnippetMatcher snippet = SnippetMatchers.snippet(); - private File outputDir; + private File outputDirectory; @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"); - } - } + this.outputDirectory = new File("build/" + + description.getTestClass().getSimpleName()); + return new ExpectedSnippetStatement(base); } private final class ExpectedSnippetStatement extends Statement { @@ -93,8 +69,8 @@ public class ExpectedSnippet implements TestRule { } private void verifySnippet() throws IOException { - if (this.outputDir != null && this.expectedName != null) { - File snippetDir = new File(this.outputDir, this.expectedName); + if (this.outputDirectory != null && this.expectedName != null) { + File snippetDir = new File(this.outputDirectory, this.expectedName); File snippetFile = new File(snippetDir, this.expectedType + ".adoc"); assertThat(snippetFile, is(this.snippet)); } @@ -150,4 +126,8 @@ public class ExpectedSnippet implements TestRule { this.snippet.withContents(matcher); } + public File getOutputDirectory() { + return this.outputDirectory; + } + } diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/test/OperationBuilder.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/test/OperationBuilder.java similarity index 86% rename from spring-restdocs/src/test/java/org/springframework/restdocs/test/OperationBuilder.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/test/OperationBuilder.java index fbb19337..e28d5751 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/test/OperationBuilder.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/test/OperationBuilder.java @@ -1,5 +1,22 @@ +/* + * 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.File; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; @@ -9,8 +26,7 @@ import java.util.Map; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; -import org.springframework.restdocs.config.RestDocumentationContext; -import org.springframework.restdocs.config.RestDocumentationContextPlaceholderResolver; +import org.springframework.restdocs.RestDocumentationContext; import org.springframework.restdocs.operation.Operation; import org.springframework.restdocs.operation.OperationRequest; import org.springframework.restdocs.operation.OperationRequestPart; @@ -20,6 +36,7 @@ import org.springframework.restdocs.operation.StandardOperation; import org.springframework.restdocs.operation.StandardOperationRequest; import org.springframework.restdocs.operation.StandardOperationRequestPart; import org.springframework.restdocs.operation.StandardOperationResponse; +import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver; import org.springframework.restdocs.snippet.StandardWriterResolver; import org.springframework.restdocs.snippet.WriterResolver; import org.springframework.restdocs.templates.StandardTemplateResourceResolver; @@ -34,10 +51,13 @@ public class OperationBuilder { private final String name; + private final File outputDirectory; + private OperationRequestBuilder requestBuilder; - public OperationBuilder(String name) { + public OperationBuilder(String name, File outputDirectory) { this.name = name; + this.outputDirectory = outputDirectory; } public OperationRequestBuilder request(String uri) { @@ -59,7 +79,8 @@ public class OperationBuilder { this.attributes.put(TemplateEngine.class.getName(), new MustacheTemplateEngine(new StandardTemplateResourceResolver())); } - RestDocumentationContext context = new RestDocumentationContext(null); + RestDocumentationContext context = new RestDocumentationContext(null, null, + this.outputDirectory); this.attributes.put(RestDocumentationContext.class.getName(), context); this.attributes.put(WriterResolver.class.getName(), new StandardWriterResolver( new RestDocumentationContextPlaceholderResolver(context))); diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/test/SnippetMatchers.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/test/SnippetMatchers.java similarity index 100% rename from spring-restdocs/src/test/java/org/springframework/restdocs/test/SnippetMatchers.java rename to spring-restdocs-core/src/test/java/org/springframework/restdocs/test/SnippetMatchers.java diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/curl-request-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/curl-request-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/curl-request-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/curl-request-with-title.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/http-request-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/http-request-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/http-request-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/http-request-with-title.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/http-response-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/http-response-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/http-response-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/http-response-with-title.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/links-with-extra-column.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/links-with-extra-column.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/links-with-extra-column.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/links-with-extra-column.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/links-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/links-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/links-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/links-with-title.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/path-parameters-with-extra-column.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/path-parameters-with-extra-column.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/path-parameters-with-extra-column.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/path-parameters-with-extra-column.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/path-parameters-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/path-parameters-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/path-parameters-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/path-parameters-with-title.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/request-fields-with-extra-column.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/request-fields-with-extra-column.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/request-fields-with-extra-column.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/request-fields-with-extra-column.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/request-fields-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/request-fields-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/request-fields-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/request-fields-with-title.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/request-parameters-with-extra-column.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/request-parameters-with-extra-column.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/request-parameters-with-extra-column.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/request-parameters-with-extra-column.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/request-parameters-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/request-parameters-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/request-parameters-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/request-parameters-with-title.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/response-fields-with-extra-column.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/response-fields-with-extra-column.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/response-fields-with-extra-column.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/response-fields-with-extra-column.snippet diff --git a/spring-restdocs/src/test/resources/custom-snippet-templates/response-fields-with-title.snippet b/spring-restdocs-core/src/test/resources/custom-snippet-templates/response-fields-with-title.snippet similarity index 100% rename from spring-restdocs/src/test/resources/custom-snippet-templates/response-fields-with-title.snippet rename to spring-restdocs-core/src/test/resources/custom-snippet-templates/response-fields-with-title.snippet diff --git a/spring-restdocs/src/test/resources/field-payloads/multiple-fields-and-embedded-and-links.json b/spring-restdocs-core/src/test/resources/field-payloads/multiple-fields-and-embedded-and-links.json similarity index 100% rename from spring-restdocs/src/test/resources/field-payloads/multiple-fields-and-embedded-and-links.json rename to spring-restdocs-core/src/test/resources/field-payloads/multiple-fields-and-embedded-and-links.json diff --git a/spring-restdocs/src/test/resources/field-payloads/multiple-fields-and-embedded.json b/spring-restdocs-core/src/test/resources/field-payloads/multiple-fields-and-embedded.json similarity index 100% rename from spring-restdocs/src/test/resources/field-payloads/multiple-fields-and-embedded.json rename to spring-restdocs-core/src/test/resources/field-payloads/multiple-fields-and-embedded.json diff --git a/spring-restdocs/src/test/resources/field-payloads/multiple-fields-and-links.json b/spring-restdocs-core/src/test/resources/field-payloads/multiple-fields-and-links.json similarity index 100% rename from spring-restdocs/src/test/resources/field-payloads/multiple-fields-and-links.json rename to spring-restdocs-core/src/test/resources/field-payloads/multiple-fields-and-links.json diff --git a/spring-restdocs/src/test/resources/field-payloads/multiple-fields.json b/spring-restdocs-core/src/test/resources/field-payloads/multiple-fields.json similarity index 100% rename from spring-restdocs/src/test/resources/field-payloads/multiple-fields.json rename to spring-restdocs-core/src/test/resources/field-payloads/multiple-fields.json diff --git a/spring-restdocs/src/test/resources/field-payloads/no-fields.json b/spring-restdocs-core/src/test/resources/field-payloads/no-fields.json similarity index 100% rename from spring-restdocs/src/test/resources/field-payloads/no-fields.json rename to spring-restdocs-core/src/test/resources/field-payloads/no-fields.json diff --git a/spring-restdocs/src/test/resources/field-payloads/single-field.json b/spring-restdocs-core/src/test/resources/field-payloads/single-field.json similarity index 100% rename from spring-restdocs/src/test/resources/field-payloads/single-field.json rename to spring-restdocs-core/src/test/resources/field-payloads/single-field.json diff --git a/spring-restdocs/src/test/resources/link-payloads/atom/multiple-links-different-rels.json b/spring-restdocs-core/src/test/resources/link-payloads/atom/multiple-links-different-rels.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/atom/multiple-links-different-rels.json rename to spring-restdocs-core/src/test/resources/link-payloads/atom/multiple-links-different-rels.json diff --git a/spring-restdocs/src/test/resources/link-payloads/atom/multiple-links-same-rels.json b/spring-restdocs-core/src/test/resources/link-payloads/atom/multiple-links-same-rels.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/atom/multiple-links-same-rels.json rename to spring-restdocs-core/src/test/resources/link-payloads/atom/multiple-links-same-rels.json diff --git a/spring-restdocs/src/test/resources/link-payloads/atom/no-links.json b/spring-restdocs-core/src/test/resources/link-payloads/atom/no-links.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/atom/no-links.json rename to spring-restdocs-core/src/test/resources/link-payloads/atom/no-links.json diff --git a/spring-restdocs/src/test/resources/link-payloads/atom/single-link.json b/spring-restdocs-core/src/test/resources/link-payloads/atom/single-link.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/atom/single-link.json rename to spring-restdocs-core/src/test/resources/link-payloads/atom/single-link.json diff --git a/spring-restdocs/src/test/resources/link-payloads/atom/wrong-format.json b/spring-restdocs-core/src/test/resources/link-payloads/atom/wrong-format.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/atom/wrong-format.json rename to spring-restdocs-core/src/test/resources/link-payloads/atom/wrong-format.json diff --git a/spring-restdocs/src/test/resources/link-payloads/hal/multiple-links-different-rels.json b/spring-restdocs-core/src/test/resources/link-payloads/hal/multiple-links-different-rels.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/hal/multiple-links-different-rels.json rename to spring-restdocs-core/src/test/resources/link-payloads/hal/multiple-links-different-rels.json diff --git a/spring-restdocs/src/test/resources/link-payloads/hal/multiple-links-same-rels.json b/spring-restdocs-core/src/test/resources/link-payloads/hal/multiple-links-same-rels.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/hal/multiple-links-same-rels.json rename to spring-restdocs-core/src/test/resources/link-payloads/hal/multiple-links-same-rels.json diff --git a/spring-restdocs/src/test/resources/link-payloads/hal/no-links.json b/spring-restdocs-core/src/test/resources/link-payloads/hal/no-links.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/hal/no-links.json rename to spring-restdocs-core/src/test/resources/link-payloads/hal/no-links.json diff --git a/spring-restdocs/src/test/resources/link-payloads/hal/single-link.json b/spring-restdocs-core/src/test/resources/link-payloads/hal/single-link.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/hal/single-link.json rename to spring-restdocs-core/src/test/resources/link-payloads/hal/single-link.json diff --git a/spring-restdocs/src/test/resources/link-payloads/hal/wrong-format.json b/spring-restdocs-core/src/test/resources/link-payloads/hal/wrong-format.json similarity index 100% rename from spring-restdocs/src/test/resources/link-payloads/hal/wrong-format.json rename to spring-restdocs-core/src/test/resources/link-payloads/hal/wrong-format.json diff --git a/spring-restdocs/src/test/resources/org/springframework/restdocs/constraints/TestConstraintDescriptions.properties b/spring-restdocs-core/src/test/resources/org/springframework/restdocs/constraints/TestConstraintDescriptions.properties similarity index 100% rename from spring-restdocs/src/test/resources/org/springframework/restdocs/constraints/TestConstraintDescriptions.properties rename to spring-restdocs-core/src/test/resources/org/springframework/restdocs/constraints/TestConstraintDescriptions.properties diff --git a/spring-restdocs-mockmvc/build.gradle b/spring-restdocs-mockmvc/build.gradle new file mode 100644 index 00000000..59774105 --- /dev/null +++ b/spring-restdocs-mockmvc/build.gradle @@ -0,0 +1,14 @@ +dependencies { + compile 'org.springframework:spring-test' + compile project(':spring-restdocs-core') + + testCompile 'org.mockito:mockito-core' + testCompile 'org.hamcrest:hamcrest-library' + testCompile 'org.springframework.hateoas:spring-hateoas' + testCompile project(path: ':spring-restdocs-core', configuration: 'testArtifacts') + testRuntime 'commons-logging:commons-logging:1.2' +} + +test { + jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=org.springframework.restdocs.*" +} \ No newline at end of file diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/AbstractConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/AbstractConfigurer.java similarity index 95% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/AbstractConfigurer.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/AbstractConfigurer.java index f8453058..ebb0a4c4 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/AbstractConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/AbstractConfigurer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.restdocs.config; +package org.springframework.restdocs.mockmvc; import org.springframework.mock.web.MockHttpServletRequest; diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/AbstractNestedConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/AbstractNestedConfigurer.java similarity index 97% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/AbstractNestedConfigurer.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/AbstractNestedConfigurer.java index ce542926..57153d70 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/AbstractNestedConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/AbstractNestedConfigurer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.restdocs.config; +package org.springframework.restdocs.mockmvc; import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder; diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/MockMvcOperationRequestFactory.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactory.java similarity index 91% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/MockMvcOperationRequestFactory.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactory.java index 60c82404..70d4351e 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/MockMvcOperationRequestFactory.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactory.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.springframework.restdocs.operation; +package org.springframework.restdocs.mockmvc; -import static org.springframework.restdocs.util.IterableEnumeration.iterable; +import static org.springframework.restdocs.mockmvc.util.IterableEnumeration.iterable; import java.io.IOException; import java.io.PrintWriter; @@ -34,6 +34,11 @@ import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockMultipartHttpServletRequest; +import org.springframework.restdocs.operation.OperationRequest; +import org.springframework.restdocs.operation.OperationRequestPart; +import org.springframework.restdocs.operation.Parameters; +import org.springframework.restdocs.operation.StandardOperationRequest; +import org.springframework.restdocs.operation.StandardOperationRequestPart; import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; @@ -45,7 +50,7 @@ import org.springframework.web.multipart.MultipartFile; * @author Andy Wilkinson * */ -public class MockMvcOperationRequestFactory { +class MockMvcOperationRequestFactory { private static final String SCHEME_HTTP = "http"; diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/MockMvcOperationResponseFactory.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationResponseFactory.java similarity index 88% rename from spring-restdocs/src/main/java/org/springframework/restdocs/operation/MockMvcOperationResponseFactory.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationResponseFactory.java index 5ace0f06..0f6f6b8a 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/MockMvcOperationResponseFactory.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationResponseFactory.java @@ -14,11 +14,13 @@ * limitations under the License. */ -package org.springframework.restdocs.operation; +package org.springframework.restdocs.mockmvc; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.restdocs.operation.OperationResponse; +import org.springframework.restdocs.operation.StandardOperationResponse; /** * A factory for creating an {@link OperationResponse} derived from a @@ -26,7 +28,7 @@ import org.springframework.mock.web.MockHttpServletResponse; * * @author Andy Wilkinson */ -public class MockMvcOperationResponseFactory { +class MockMvcOperationResponseFactory { /** * Create a new {@code OperationResponse} derived from the given {@code mockResponse}. diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentation.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java similarity index 90% rename from spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentation.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java index 952ca423..2a2cc2d6 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentation.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.springframework.restdocs; +package org.springframework.restdocs.mockmvc; -import org.springframework.restdocs.config.RestDocumentationConfigurer; +import org.springframework.restdocs.RestDocumentation; import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; import org.springframework.restdocs.snippet.Snippet; @@ -30,21 +30,23 @@ import org.springframework.test.web.servlet.setup.MockMvcConfigurer; * * @author Andy Wilkinson */ -public abstract class RestDocumentation { +public abstract class MockMvcRestDocumentation { - private RestDocumentation() { + private MockMvcRestDocumentation() { } /** - * Provides access to a {@link MockMvcConfigurer} that can be used to configure the - * REST documentation when building a {@link MockMvc} instance. + * Provides access to a {@link MockMvcConfigurer} that can be used to configure a + * {@link MockMvc} instance using the given {@code restDocumentation}. * - * @see ConfigurableMockMvcBuilder#apply(MockMvcConfigurer) + * @param restDocumentation the REST documentation * @return the configurer + * @see ConfigurableMockMvcBuilder#apply(MockMvcConfigurer) */ - public static RestDocumentationConfigurer documentationConfiguration() { - return new RestDocumentationConfigurer(); + public static RestDocumentationMockMvcConfigurer documentationConfiguration( + RestDocumentation restDocumentation) { + return new RestDocumentationMockMvcConfigurer(restDocumentation); } /** diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/NestedConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/NestedConfigurer.java similarity index 86% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/NestedConfigurer.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/NestedConfigurer.java index 25c57767..2fc73bb3 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/NestedConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/NestedConfigurer.java @@ -14,17 +14,17 @@ * limitations under the License. */ -package org.springframework.restdocs.config; +package org.springframework.restdocs.mockmvc; import org.springframework.test.web.servlet.setup.MockMvcConfigurer; /** * A configurer that is nested and, therefore, has a parent. * - * @author awilkinson + * @author Andy Wilkinson * @param The parent's type */ -public interface NestedConfigurer { +interface NestedConfigurer { /** * Returns the configurer's parent diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationMockMvcConfigurer.java similarity index 79% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationMockMvcConfigurer.java index 2f9417b9..e13025eb 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationMockMvcConfigurer.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package org.springframework.restdocs.config; - -import java.util.Arrays; -import java.util.List; +package org.springframework.restdocs.mockmvc; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.restdocs.RestDocumentation; +import org.springframework.restdocs.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; @@ -39,9 +38,9 @@ import org.springframework.web.context.WebApplicationContext; * @author Andy Wilkinson * @author Dmitriy Mayboroda * @see ConfigurableMockMvcBuilder#apply(MockMvcConfigurer) - * @see RestDocumentation#documentationConfiguration() + * @see MockMvcRestDocumentation#documentationConfiguration(RestDocumentation) */ -public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter { +public class RestDocumentationMockMvcConfigurer extends MockMvcConfigurerAdapter { private final UriConfigurer uriConfigurer = new UriConfigurer(this); @@ -54,15 +53,17 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter { private final WriterResolverConfigurer writerResolverConfigurer = new WriterResolverConfigurer(); /** - * Creates a new {@link RestDocumentationConfigurer}. - * @see RestDocumentation#documentationConfiguration() + * Creates a new {code RestDocumentationMockMvcConfigurer} that will use the given + * {@code restDocumentation} when configuring MockMvc. + * + * @param restDocumentation the rest documentation + * @see MockMvcRestDocumentation#documentationConfiguration(RestDocumentation) */ - public RestDocumentationConfigurer() { + RestDocumentationMockMvcConfigurer(RestDocumentation restDocumentation) { this.requestPostProcessor = new ConfigurerApplyingRequestPostProcessor( - Arrays. asList(this.uriConfigurer, - this.writerResolverConfigurer, this.snippetConfigurer, - new StepCountConfigurer(), new ContentLengthHeaderConfigurer(), - this.templateEngineConfigurer)); + restDocumentation, this.uriConfigurer, this.writerResolverConfigurer, + this.snippetConfigurer, new ContentLengthHeaderConfigurer(), + this.templateEngineConfigurer); } /** @@ -91,7 +92,7 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter { * @param templateEngine the template engine to use * @return {@code this} */ - public RestDocumentationConfigurer templateEngine(TemplateEngine templateEngine) { + public RestDocumentationMockMvcConfigurer templateEngine(TemplateEngine templateEngine) { this.templateEngineConfigurer.setTemplateEngine(templateEngine); return this; } @@ -103,7 +104,7 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter { * @param writerResolver The writer resolver to use * @return {@code this} */ - public RestDocumentationConfigurer writerResolver(WriterResolver writerResolver) { + public RestDocumentationMockMvcConfigurer writerResolver(WriterResolver writerResolver) { this.writerResolverConfigurer.setWriterResolver(writerResolver); return this; } @@ -114,19 +115,6 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter { return this.requestPostProcessor; } - private static class StepCountConfigurer extends AbstractConfigurer { - - @Override - void apply(MockHttpServletRequest request) { - RestDocumentationContext context = (RestDocumentationContext) request - .getAttribute(RestDocumentationContext.class.getName()); - if (context != null) { - context.getAndIncrementStepCount(); - } - } - - } - private static class ContentLengthHeaderConfigurer extends AbstractConfigurer { @Override @@ -182,17 +170,20 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter { private static class ConfigurerApplyingRequestPostProcessor implements RequestPostProcessor { - private final List configurers; + private final RestDocumentation restDocumentation; + + private final AbstractConfigurer[] configurers; private ConfigurerApplyingRequestPostProcessor( - List configurers) { + RestDocumentation restDocumentation, AbstractConfigurer... configurers) { + this.restDocumentation = restDocumentation; this.configurers = configurers; } @Override public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { request.setAttribute(RestDocumentationContext.class.getName(), - RestDocumentationContextHolder.getCurrentContext()); + this.restDocumentation.beforeOperation()); for (AbstractConfigurer configurer : this.configurers) { configurer.apply(request); } diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentationRequestBuilders.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationRequestBuilders.java similarity index 99% rename from spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentationRequestBuilders.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationRequestBuilders.java index 160006d4..dc6f7a25 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentationRequestBuilders.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationRequestBuilders.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.restdocs; +package org.springframework.restdocs.mockmvc; import java.net.URI; diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentationResultHandler.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java similarity index 93% rename from spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentationResultHandler.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java index e1fc99f1..2a7e4ab4 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/RestDocumentationResultHandler.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.springframework.restdocs; +package org.springframework.restdocs.mockmvc; -import static org.springframework.restdocs.util.IterableEnumeration.iterable; +import static org.springframework.restdocs.mockmvc.util.IterableEnumeration.iterable; import java.util.ArrayList; import java.util.Arrays; @@ -24,8 +24,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.springframework.restdocs.operation.MockMvcOperationRequestFactory; -import org.springframework.restdocs.operation.MockMvcOperationResponseFactory; import org.springframework.restdocs.operation.Operation; import org.springframework.restdocs.operation.OperationRequest; import org.springframework.restdocs.operation.OperationResponse; @@ -42,7 +40,7 @@ import org.springframework.util.Assert; * * @author Andy Wilkinson * @author Andreas Evers - * @see RestDocumentation#document(String, Snippet...) + * @see MockMvcRestDocumentation#document(String, Snippet...) */ public class RestDocumentationResultHandler implements ResultHandler { diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/SnippetConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/SnippetConfigurer.java similarity index 93% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/SnippetConfigurer.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/SnippetConfigurer.java index 992086f7..ace722ea 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/SnippetConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/SnippetConfigurer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.restdocs.config; +package org.springframework.restdocs.mockmvc; import java.util.Arrays; import java.util.List; @@ -29,10 +29,9 @@ import org.springframework.restdocs.snippet.WriterResolver; * A configurer that can be used to configure the generated documentation snippets. * * @author Andy Wilkinson - * */ public class SnippetConfigurer extends - AbstractNestedConfigurer { + AbstractNestedConfigurer { private List defaultSnippets = Arrays.asList( CurlDocumentation.curlRequest(), HttpDocumentation.httpRequest(), @@ -46,7 +45,7 @@ public class SnippetConfigurer extends private String snippetEncoding = DEFAULT_SNIPPET_ENCODING; - SnippetConfigurer(RestDocumentationConfigurer parent) { + SnippetConfigurer(RestDocumentationMockMvcConfigurer parent) { super(parent); } diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/UriConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/UriConfigurer.java similarity index 93% rename from spring-restdocs/src/main/java/org/springframework/restdocs/config/UriConfigurer.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/UriConfigurer.java index 30baa03c..c931ea96 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/UriConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/UriConfigurer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.restdocs.config; +package org.springframework.restdocs.mockmvc; import org.springframework.mock.web.MockHttpServletRequest; @@ -23,7 +23,7 @@ import org.springframework.mock.web.MockHttpServletRequest; * * @author Andy Wilkinson */ -public class UriConfigurer extends AbstractNestedConfigurer { +public class UriConfigurer extends AbstractNestedConfigurer { /** * The default scheme for documented URIs @@ -49,7 +49,7 @@ public class UriConfigurer extends AbstractNestedConfigurer - repackJar.baseName = "restdocs-jmustache-repack" - repackJar.version = dependencyManagement.managedVersions['com.samskivert:jmustache'] - - doLast() { - project.ant { - taskdef name: "jarjar", classname: "com.tonicsystems.jarjar.JarJarTask", - classpath: configurations.jarjar.asPath - jarjar(destfile: repackJar.archivePath) { - configurations.jmustache.each { originalJar -> - zipfileset(src: originalJar, includes: '**/*.class') - } - rule(pattern: 'com.samskivert.**', result: 'org.springframework.restdocs.@1') - } - } - } -} - -dependencies { - compile 'com.fasterxml.jackson.core:jackson-databind' - compile 'junit:junit' - compile 'org.springframework:spring-core' - compile 'org.springframework:spring-test' - compile 'org.springframework:spring-web' - compile 'org.springframework:spring-webmvc' - compile 'javax.servlet:javax.servlet-api' - compile files(jmustacheRepackJar) - jacoco 'org.jacoco:org.jacoco.agent::runtime' - jarjar 'com.googlecode.jarjar:jarjar:1.3' - jmustache 'com.samskivert:jmustache@jar' - optional 'javax.validation:validation-api' - testCompile 'org.springframework.hateoas:spring-hateoas' - testCompile 'org.mockito:mockito-core' - testCompile 'org.hamcrest:hamcrest-core' - testCompile 'org.hamcrest:hamcrest-library' - testCompile 'org.hibernate:hibernate-validator' - testRuntime 'org.glassfish:javax.el:3.0.0' -} - -jar { - dependsOn jmustacheRepackJar - from(zipTree(jmustacheRepackJar.archivePath)) { - include "org/springframework/restdocs/**" - } -} - -task sourcesJar(type: Jar) { - classifier = 'sources' - from project.sourceSets.main.allSource -} - -javadoc { - description = "Generates project-level javadoc for use in -javadoc jar" - options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED - options.author = true - options.header = "Spring REST Docs $version" - options.docTitle = "${options.header} API" - options.links = [ - 'http://docs.oracle.com/javase/8/docs/api/', - "http://docs.spring.io/spring-framework/docs/${dependencyManagement.managedVersions['org.springframework:spring-core']}/javadoc-api/", - 'https://docs.jboss.org/hibernate/stable/beanvalidation/api/' - ] as String[] - options.addStringOption '-quiet' -} - -task javadocJar(type: Jar) { - classifier = "javadoc" - from javadoc -} - -artifacts { - archives sourcesJar - archives javadocJar -} - -test { - jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=org.springframework.restdocs.*,excludes=org.springframework.restdocs.mustache.*" - testLogging { - exceptionFormat "full" - } -} \ No newline at end of file diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContext.java b/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContext.java deleted file mode 100644 index 2a95a7f1..00000000 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationContext.java +++ /dev/null @@ -1,73 +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.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 final AtomicInteger stepCount = new AtomicInteger(0); - - private final TestContext testContext; - - /** - * Creates a new {@code RestDocumentationContext} backed by the given - * {@code testContext}. - * - * @param testContext the test context - */ - 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.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() { - return this.stepCount.getAndIncrement(); - } - - /** - * Gets the current step count - * - * @return The current step count - */ - public int getStepCount() { - return this.stepCount.get(); - } - -} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationTestExecutionListener.java b/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationTestExecutionListener.java deleted file mode 100644 index 7189ad0a..00000000 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/config/RestDocumentationTestExecutionListener.java +++ /dev/null @@ -1,41 +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.config; - -import org.springframework.test.context.TestContext; -import org.springframework.test.context.TestExecutionListener; -import org.springframework.test.context.support.AbstractTestExecutionListener; - -/** - * A {@link TestExecutionListener} that sets up and tears down the Spring REST Docs - * context for each test method - * - * @author Andy Wilkinson - */ -public class RestDocumentationTestExecutionListener extends AbstractTestExecutionListener { - - @Override - public void beforeTestMethod(TestContext testContext) throws Exception { - RestDocumentationContextHolder.setCurrentContext(new RestDocumentationContext( - testContext)); - } - - @Override - public void afterTestMethod(TestContext testContext) throws Exception { - RestDocumentationContextHolder.removeCurrentContext(); - } -} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java b/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java deleted file mode 100644 index a8ea46fc..00000000 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/operation/preprocess/OperationResponsePreprocessor.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.springframework.restdocs.operation.preprocess; - -import org.springframework.restdocs.operation.OperationResponse; - -/** - * An {@code OperationRequestPreprocessor} is used to modify an {@code OperationRequest} - * prior to it being documented. - * - * @author Andy Wilkinson - */ -public interface OperationResponsePreprocessor { - - /** - * Processes and potentially modifies the given {@code response} before it is - * documented. - * - * @param response the response - * @return the modified response - */ - OperationResponse preprocess(OperationResponse response); - -} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java b/spring-restdocs/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java deleted file mode 100644 index a569b39b..00000000 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/payload/PayloadHandlingException.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.springframework.restdocs.payload; - -/** - * Thrown to indicate that a failure has occurred during payload handling - * - * @author Andy Wilkinson - * - */ -@SuppressWarnings("serial") -class PayloadHandlingException extends RuntimeException { - - /** - * Creates a new {@code PayloadHandlingException} with the given cause - * @param cause the cause of the failure - */ - PayloadHandlingException(Throwable cause) { - super(cause); - } - -} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/DocumentationProperties.java b/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/DocumentationProperties.java deleted file mode 100644 index 3241ce04..00000000 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/snippet/DocumentationProperties.java +++ /dev/null @@ -1,52 +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.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -import org.springframework.util.StringUtils; - -class DocumentationProperties { - - private final Properties properties = new Properties(); - - DocumentationProperties() { - try (InputStream stream = getClass().getClassLoader().getResourceAsStream( - "documentation.properties")) { - if (stream != null) { - this.properties.load(stream); - } - } - catch (IOException ex) { - throw new IllegalStateException("Failed to read documentation.properties", ex); - } - - this.properties.putAll(System.getProperties()); - } - - File getOutputDir() { - String outputDir = this.properties - .getProperty("org.springframework.restdocs.outputDir"); - if (StringUtils.hasText(outputDir)) { - return new File(outputDir).getAbsoluteFile(); - } - return null; - } -} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/templates/Template.java b/spring-restdocs/src/main/java/org/springframework/restdocs/templates/Template.java deleted file mode 100644 index 302e5f6c..00000000 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/templates/Template.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.springframework.restdocs.templates; - -import java.util.Map; - -/** - * A compiled {@code Template} that can be rendered to a {@link String}. - * - * @author Andy Wilkinson - * - */ -public interface Template { - - /** - * Renders the template to a {@link String} using the given {@code context} for - * variable/property resolution. - * - * @param context The context to use - * @return The rendered template - */ - String render(Map context); - -} diff --git a/spring-restdocs/src/main/resources/META-INF/spring.factories b/spring-restdocs/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 64519d78..00000000 --- a/spring-restdocs/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.test.context.TestExecutionListener=org.springframework.restdocs.config.RestDocumentationTestExecutionListener \ No newline at end of file diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/config/RestDocumentationContexts.java b/spring-restdocs/src/test/java/org/springframework/restdocs/config/RestDocumentationContexts.java deleted file mode 100644 index 629d6908..00000000 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/config/RestDocumentationContexts.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.springframework.restdocs.config; - - -public class RestDocumentationContexts { - -} diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java b/spring-restdocs/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java deleted file mode 100644 index 03b21641..00000000 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/snippet/RestDocumentationContextPlaceholderResolverTests.java +++ /dev/null @@ -1,61 +0,0 @@ -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.restdocs.config.RestDocumentationContextPlaceholderResolver; -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")); - } - -}