Merge branch '2.0.x'
This commit is contained in:
7
config/checkstyle/checkstyle-suppressions.xml
Normal file
7
config/checkstyle/checkstyle-suppressions.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
|
||||
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
|
||||
<suppressions>
|
||||
<suppress files="com[\\/]example[\\/]restassured" checks="IllegalImport" />
|
||||
</suppressions>
|
||||
@@ -1,8 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
<module name="com.puppycrawl.tools.checkstyle.Checker">
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${config_loc}/checkstyle-suppressions.xml"/>
|
||||
</module>
|
||||
<module name="io.spring.javaformat.checkstyle.SpringChecks">
|
||||
<property name="avoidStaticImportExcludes" value=" org.springframework.restdocs.cli.CliDocumentation.*"/>
|
||||
</module>
|
||||
|
||||
<module name="com.puppycrawl.tools.checkstyle.TreeWalker">
|
||||
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
||||
<property name="regexp" value="true" />
|
||||
<property name="illegalPkgs" value="^org\.hamcrest.*" />
|
||||
</module>
|
||||
</module>
|
||||
</module>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -23,11 +23,10 @@ import java.util.Map;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link SnippetsDirectoryResolver}.
|
||||
@@ -39,9 +38,6 @@ public class SnippetsDirectoryResolverTests {
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void mavenProjectsUseTargetGeneratedSnippetsRelativeToDocdir() throws IOException {
|
||||
this.temporaryFolder.newFile("pom.xml");
|
||||
@@ -57,17 +53,15 @@ public class SnippetsDirectoryResolverTests {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
String docdir = new File(this.temporaryFolder.getRoot(), "src/main/asciidoc").getAbsolutePath();
|
||||
attributes.put("docdir", docdir);
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage(equalTo("pom.xml not found in '" + docdir + "' or above"));
|
||||
getMavenSnippetsDirectory(attributes);
|
||||
assertThatIllegalStateException().isThrownBy(() -> getMavenSnippetsDirectory(attributes))
|
||||
.withMessage("pom.xml not found in '" + docdir + "' or above");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalStateWhenDocdirAttributeIsNotSetInMavenProject() throws IOException {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage(equalTo("docdir attribute not found"));
|
||||
getMavenSnippetsDirectory(attributes);
|
||||
assertThatIllegalStateException().isThrownBy(() -> getMavenSnippetsDirectory(attributes))
|
||||
.withMessage("docdir attribute not found");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,9 +94,9 @@ public class SnippetsDirectoryResolverTests {
|
||||
@Test
|
||||
public void illegalStateWhenGradleProjectdirAndProjectdirAttributesAreNotSetInGradleProject() throws IOException {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage(equalTo("projectdir attribute not found"));
|
||||
new SnippetsDirectoryResolver().getSnippetsDirectory(attributes);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> new SnippetsDirectoryResolver().getSnippetsDirectory(attributes))
|
||||
.withMessage("projectdir attribute not found");
|
||||
}
|
||||
|
||||
private File getMavenSnippetsDirectory(Map<String, Object> attributes) {
|
||||
|
||||
@@ -63,8 +63,6 @@ dependencies {
|
||||
testImplementation("org.assertj:assertj-core")
|
||||
testImplementation("org.javamoney:moneta")
|
||||
testImplementation("org.mockito:mockito-core")
|
||||
testImplementation("org.hamcrest:hamcrest-core")
|
||||
testImplementation("org.hamcrest:hamcrest-library")
|
||||
testImplementation("org.springframework:spring-test")
|
||||
|
||||
testRuntimeOnly("org.glassfish:jakarta.el:4.0.2")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -21,14 +21,12 @@ import java.util.Arrays;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
|
||||
|
||||
/**
|
||||
@@ -42,25 +40,21 @@ public class RequestHeadersSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void missingRequestHeader() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Headers with the following names were not found" + " in the request: [Accept]"));
|
||||
new RequestHeadersSnippet(Arrays.asList(headerWithName("Accept").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestHeadersSnippet(Arrays.asList(headerWithName("Accept").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build()))
|
||||
.withMessage("Headers with the following names were not found in the request: [Accept]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedRequestHeaderAndMissingRequestHeader() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
endsWith("Headers with the following names were not found" + " in the request: [Accept]"));
|
||||
new RequestHeadersSnippet(Arrays.asList(headerWithName("Accept").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").header("X-Test", "test").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestHeadersSnippet(Arrays.asList(headerWithName("Accept").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").header("X-Test", "test").build()))
|
||||
.withMessageEndingWith("Headers with the following names were not found in the request: [Accept]");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -21,14 +21,12 @@ import java.util.Arrays;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
|
||||
|
||||
/**
|
||||
@@ -42,25 +40,21 @@ public class ResponseHeadersSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void missingResponseHeader() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Headers with the following names were not found" + " in the response: [Content-Type]"));
|
||||
new ResponseHeadersSnippet(Arrays.asList(headerWithName("Content-Type").description("one")))
|
||||
.document(this.operationBuilder.response().build());
|
||||
assertThatExceptionOfType(SnippetException.class).isThrownBy(
|
||||
() -> new ResponseHeadersSnippet(Arrays.asList(headerWithName("Content-Type").description("one")))
|
||||
.document(this.operationBuilder.response().build()))
|
||||
.withMessage("Headers with the following names were not found" + " in the response: [Content-Type]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedResponseHeaderAndMissingResponseHeader() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
endsWith("Headers with the following names were not found" + " in the response: [Content-Type]"));
|
||||
new ResponseHeadersSnippet(Arrays.asList(headerWithName("Content-Type").description("one")))
|
||||
.document(this.operationBuilder.response().header("X-Test", "test").build());
|
||||
assertThatExceptionOfType(SnippetException.class).isThrownBy(
|
||||
() -> new ResponseHeadersSnippet(Arrays.asList(headerWithName("Content-Type").description("one")))
|
||||
.document(this.operationBuilder.response().header("X-Test", "test").build()))
|
||||
.withMessageEndingWith(
|
||||
"Headers with the following names were not found in the response: [Content-Type]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -22,13 +22,12 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for failures when rendering {@link LinksSnippet} due to missing or undocumented
|
||||
@@ -41,42 +40,40 @@ public class LinksSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void undocumentedLink() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Links with the following relations were not" + " documented: [foo]"));
|
||||
new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "bar")),
|
||||
Collections.<LinkDescriptor>emptyList()).document(this.operationBuilder.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "bar")),
|
||||
Collections.<LinkDescriptor>emptyList()).document(this.operationBuilder.build()))
|
||||
.withMessage("Links with the following relations were not documented: [foo]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingLink() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
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(this.operationBuilder.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new LinksSnippet(new StubLinkExtractor(),
|
||||
Arrays.asList(new LinkDescriptor("foo").description("bar")))
|
||||
.document(this.operationBuilder.build()))
|
||||
.withMessage("Links with the following relations were not found in the response: [foo]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedLinkAndMissingLink() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Links with the following relations were not"
|
||||
+ " documented: [a]. Links with the following relations were not" + " found in the response: [foo]"));
|
||||
new LinksSnippet(new StubLinkExtractor().withLinks(new Link("a", "alpha")),
|
||||
Arrays.asList(new LinkDescriptor("foo").description("bar"))).document(this.operationBuilder.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new LinksSnippet(new StubLinkExtractor().withLinks(new Link("a", "alpha")),
|
||||
Arrays.asList(new LinkDescriptor("foo").description("bar")))
|
||||
.document(this.operationBuilder.build()))
|
||||
.withMessage("Links with the following relations were not documented: [a]. Links with the following"
|
||||
+ " relations were not found in the response: [foo]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkWithNoDescription() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("No description was provided for the link with rel 'foo' and no"
|
||||
+ " title was available from the link in the payload"));
|
||||
new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "bar")),
|
||||
Arrays.asList(new LinkDescriptor("foo"))).document(this.operationBuilder.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "bar")),
|
||||
Arrays.asList(new LinkDescriptor("foo"))).document(this.operationBuilder.build()))
|
||||
.withMessage("No description was provided for the link with rel 'foo' and no title was available"
|
||||
+ " from the link in the payload");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,12 +19,10 @@ package org.springframework.restdocs.operation;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link QueryStringParser}.
|
||||
@@ -33,9 +31,6 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||
*/
|
||||
public class QueryStringParserTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final QueryStringParser queryStringParser = new QueryStringParser();
|
||||
|
||||
@Test
|
||||
@@ -76,9 +71,9 @@ public class QueryStringParserTests {
|
||||
|
||||
@Test
|
||||
public void malformedParameter() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage(equalTo("The parameter 'a=apple=avocado' is malformed"));
|
||||
this.queryStringParser.parse(URI.create("http://localhost?a=apple=avocado"));
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.queryStringParser.parse(URI.create("http://localhost?a=apple=avocado")))
|
||||
.withMessage("The parameter 'a=apple=avocado' is malformed");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -23,10 +23,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.restdocs.testfixtures.OutputCapture;
|
||||
import org.springframework.restdocs.testfixtures.OutputCaptureRule;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.isEmptyString;
|
||||
|
||||
/**
|
||||
* Tests for {@link PrettyPrintingContentModifier}.
|
||||
@@ -37,7 +36,7 @@ import static org.hamcrest.Matchers.isEmptyString;
|
||||
public class PrettyPrintingContentModifierTests {
|
||||
|
||||
@Rule
|
||||
public OutputCapture outputCapture = new OutputCapture();
|
||||
public OutputCaptureRule outputCapture = new OutputCaptureRule();
|
||||
|
||||
@Test
|
||||
public void prettyPrintJson() throws Exception {
|
||||
@@ -61,17 +60,17 @@ public class PrettyPrintingContentModifierTests {
|
||||
@Test
|
||||
public void nonJsonAndNonXmlContentIsHandledGracefully() throws Exception {
|
||||
String content = "abcdefg";
|
||||
this.outputCapture.expect(isEmptyString());
|
||||
assertThat(new PrettyPrintingContentModifier().modifyContent(content.getBytes(), null))
|
||||
.isEqualTo(content.getBytes());
|
||||
assertThat(this.outputCapture).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonJsonContentThatInitiallyLooksLikeJsonIsHandledGracefully() throws Exception {
|
||||
String content = "\"abc\",\"def\"";
|
||||
this.outputCapture.expect(isEmptyString());
|
||||
assertThat(new PrettyPrintingContentModifier().modifyContent(content.getBytes(), null))
|
||||
.isEqualTo(content.getBytes());
|
||||
assertThat(this.outputCapture).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -22,7 +22,6 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -30,9 +29,7 @@ import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
|
||||
/**
|
||||
@@ -46,148 +43,145 @@ public class RequestFieldsSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void undocumentedRequestField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not" + " documented:"));
|
||||
new RequestFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").content("{\"a\": 5}").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").content("{\"a\": 5}").build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingRequestField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.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(this.operationBuilder.request("http://localhost").content("{}").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("{}").build()))
|
||||
.withMessage("Fields with the following paths were not found in the payload: [a.b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingOptionalRequestFieldWithNoTypeProvided() throws IOException {
|
||||
this.thrown.expect(FieldTypeRequiredException.class);
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one").optional()))
|
||||
.document(this.operationBuilder.request("http://localhost").content("{ }").build());
|
||||
assertThatExceptionOfType(FieldTypeRequiredException.class).isThrownBy(
|
||||
() -> new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one").optional()))
|
||||
.document(this.operationBuilder.request("http://localhost").content("{ }").build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedRequestFieldAndMissingRequestField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not" + " documented:"));
|
||||
this.thrown
|
||||
.expectMessage(endsWith("Fields with the following paths were not found" + " in the payload: [a.b]"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("{ \"a\": { \"c\": 5 }}").build());
|
||||
assertThatExceptionOfType(SnippetException.class).isThrownBy(
|
||||
() -> new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a.b").description("one"))).document(
|
||||
this.operationBuilder.request("http://localhost").content("{ \"a\": { \"c\": 5 }}").build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:")
|
||||
.withMessageEndingWith("Fields with the following paths were not found in the payload: [a.b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attemptToDocumentFieldsWithNoRequestBody() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Cannot document request fields as the request body is empty"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build()))
|
||||
.withMessage("Cannot document request fields as the request body is empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fieldWithExplicitTypeThatDoesNotMatchThePayload() throws IOException {
|
||||
this.thrown.expect(FieldTypesDoNotMatchException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("The documented type of the field 'a' is" + " Object but the actual type is Number"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one").type(JsonFieldType.OBJECT)))
|
||||
.document(this.operationBuilder.request("http://localhost").content("{ \"a\": 5 }").build());
|
||||
assertThatExceptionOfType(FieldTypesDoNotMatchException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a").description("one").type(JsonFieldType.OBJECT))).document(
|
||||
this.operationBuilder.request("http://localhost").content("{ \"a\": 5 }").build()))
|
||||
.withMessage("The documented type of the field 'a' is Object but the actual type is Number");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fieldWithExplicitSpecificTypeThatActuallyVaries() throws IOException {
|
||||
this.thrown.expect(FieldTypesDoNotMatchException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("The documented type of the field '[].a' is" + " Object but the actual type is Varies"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("[].a").description("one").type(JsonFieldType.OBJECT)))
|
||||
.document(this.operationBuilder.request("http://localhost").content("[{ \"a\": 5 },{ \"a\": \"b\" }]")
|
||||
.build());
|
||||
assertThatExceptionOfType(FieldTypesDoNotMatchException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("[].a").description("one").type(JsonFieldType.OBJECT)))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.content("[{ \"a\": 5 },{ \"a\": \"b\" }]").build()))
|
||||
.withMessage("The documented type of the field '[].a' is Object but the actual type is Varies");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedXmlRequestField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not documented:"));
|
||||
new RequestFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a><b>5</b></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a><b>5</b></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlDescendentsAreNotDocumentedByFieldDescriptor() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not documented:"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").type("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a><b>5</b></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(
|
||||
() -> new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").type("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a><b>5</b></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlRequestFieldWithNoType() throws IOException {
|
||||
this.thrown.expect(FieldTypeRequiredException.class);
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a>5</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(FieldTypeRequiredException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a>5</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingXmlRequestField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Fields with the following paths were not found" + " in the payload: [a/b]"));
|
||||
new RequestFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a/b").description("one"), fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a/b").description("one"), fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessage("Fields with the following paths were not found in the payload: [a/b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedXmlRequestFieldAndMissingXmlRequestField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not documented:"));
|
||||
this.thrown
|
||||
.expectMessage(endsWith("Fields with the following paths were not found" + " in the payload: [a/b]"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a><c>5</c></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").content("<a><c>5</c></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:")
|
||||
.withMessageEndingWith("Fields with the following paths were not found in the payload: [a/b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsupportedContent() throws IOException {
|
||||
this.thrown.expect(PayloadHandlingException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Cannot handle text/plain content as it could" + " not be parsed as JSON or XML"));
|
||||
new RequestFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").content("Some plain text")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE).build());
|
||||
assertThatExceptionOfType(PayloadHandlingException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").content("Some plain text")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE).build()))
|
||||
.withMessage("Cannot handle text/plain content as it could not be parsed as JSON or XML");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonOptionalFieldBeneathArrayThatIsSometimesNull() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
startsWith("Fields with the following paths were not found in the payload: " + "[a[].b]"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.request("http://localhost").content(
|
||||
"{\"a\":[{\"b\": 1,\"c\": 2}, " + "{\"b\": null, \"c\": 2}," + " {\"b\": 1,\"c\": 2}]}")
|
||||
.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.content("{\"a\":[{\"b\": 1,\"c\": 2}, " + "{\"b\": null, \"c\": 2},"
|
||||
+ " {\"b\": 1,\"c\": 2}]}")
|
||||
.build()))
|
||||
.withMessageStartingWith("Fields with the following paths were not found in the payload: [a[].b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonOptionalFieldBeneathArrayThatIsSometimesAbsent() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
startsWith("Fields with the following paths were not found in the payload: " + "[a[].b]"));
|
||||
new RequestFieldsSnippet(Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.content("{\"a\":[{\"b\": 1,\"c\": 2}, " + "{\"c\": 2}, {\"b\": 1,\"c\": 2}]}")
|
||||
.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.content("{\"a\":[{\"b\": 1,\"c\": 2}, "
|
||||
+ "{\"c\": 2}, {\"b\": 1,\"c\": 2}]}")
|
||||
.build()))
|
||||
.withMessageStartingWith("Fields with the following paths were not found in the payload: [a[].b]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -22,14 +22,12 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
|
||||
/**
|
||||
@@ -44,32 +42,32 @@ public class RequestPartFieldsSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void undocumentedRequestPartField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not documented:"));
|
||||
new RequestPartFieldsSnippet("part", Collections.<FieldDescriptor>emptyList()).document(
|
||||
this.operationBuilder.request("http://localhost").part("part", "{\"a\": 5}".getBytes()).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestPartFieldsSnippet("part", Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.part("part", "{\"a\": 5}".getBytes()).build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingRequestPartField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not documented:"));
|
||||
new RequestPartFieldsSnippet("part", Arrays.asList(fieldWithPath("b").description("one"))).document(
|
||||
this.operationBuilder.request("http://localhost").part("part", "{\"a\": 5}".getBytes()).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(
|
||||
() -> new RequestPartFieldsSnippet("part", Arrays.asList(fieldWithPath("b").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.part("part", "{\"a\": 5}".getBytes()).build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingRequestPart() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("A request part named 'another' was not found in the request"));
|
||||
new RequestPartFieldsSnippet("another", Arrays.asList(fieldWithPath("a.b").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.part("part", "{\"a\": {\"b\": 5}}".getBytes()).build());
|
||||
assertThatExceptionOfType(SnippetException.class).isThrownBy(
|
||||
() -> new RequestPartFieldsSnippet("another", Arrays.asList(fieldWithPath("a.b").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.part("part", "{\"a\": {\"b\": 5}}".getBytes()).build()))
|
||||
.withMessage("A request part named 'another' was not found in the request");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -22,7 +22,6 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -30,9 +29,7 @@ import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
|
||||
/**
|
||||
@@ -46,124 +43,125 @@ public class ResponseFieldsSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void attemptToDocumentFieldsWithNoResponseBody() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Cannot document response fields as the response body is empty"));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.build()))
|
||||
.withMessage("Cannot document response fields as the response body is empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fieldWithExplicitTypeThatDoesNotMatchThePayload() throws IOException {
|
||||
this.thrown.expect(FieldTypesDoNotMatchException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("The documented type of the field 'a' is" + " Object but the actual type is Number"));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one").type(JsonFieldType.OBJECT)))
|
||||
.document(this.operationBuilder.response().content("{ \"a\": 5 }}").build());
|
||||
assertThatExceptionOfType(FieldTypesDoNotMatchException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a").description("one").type(JsonFieldType.OBJECT)))
|
||||
.document(this.operationBuilder.response().content("{ \"a\": 5 }}").build()))
|
||||
.withMessage("The documented type of the field 'a' is Object but the actual type is Number");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fieldWithExplicitSpecificTypeThatActuallyVaries() throws IOException {
|
||||
this.thrown.expect(FieldTypesDoNotMatchException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("The documented type of the field '[].a' is" + " Object but the actual type is Varies"));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("[].a").description("one").type(JsonFieldType.OBJECT)))
|
||||
.document(this.operationBuilder.response().content("[{ \"a\": 5 },{ \"a\": \"b\" }]").build());
|
||||
assertThatExceptionOfType(FieldTypesDoNotMatchException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("[].a").description("one").type(JsonFieldType.OBJECT))).document(
|
||||
this.operationBuilder.response().content("[{ \"a\": 5 },{ \"a\": \"b\" }]").build()))
|
||||
.withMessage("The documented type of the field '[].a' is Object but the actual type is Varies");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedXmlResponseField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not" + " documented:"));
|
||||
new ResponseFieldsSnippet(Collections.<FieldDescriptor>emptyList()).document(this.operationBuilder.response()
|
||||
.content("<a><b>5</b></a>").header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.response().content("<a><b>5</b></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingXmlAttribute() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown
|
||||
.expectMessage(equalTo("Fields with the following paths were not found" + " in the payload: [a/@id]"));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one").type("b"),
|
||||
fieldWithPath("a/@id").description("two").type("c")))
|
||||
.document(this.operationBuilder.response().content("<a>foo</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(
|
||||
() -> new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one").type("b"),
|
||||
fieldWithPath("a/@id").description("two").type("c")))
|
||||
.document(
|
||||
this.operationBuilder.response().content("<a>foo</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE,
|
||||
MediaType.APPLICATION_XML_VALUE)
|
||||
.build()))
|
||||
.withMessage("Fields with the following paths were not found in the payload: [a/@id]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void documentedXmlAttributesAreRemoved() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo(String.format("The following parts of the payload were not documented:" + "%n<a>bar</a>%n")));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a/@id").description("one").type("a")))
|
||||
.document(this.operationBuilder.response().content("<a id=\"foo\">bar</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class).isThrownBy(
|
||||
() -> new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a/@id").description("one").type("a")))
|
||||
.document(this.operationBuilder.response().content("<a id=\"foo\">bar</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessage(String.format("The following parts of the payload were not documented:%n<a>bar</a>%n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlResponseFieldWithNoType() throws IOException {
|
||||
this.thrown.expect(FieldTypeRequiredException.class);
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.response().content("<a>5</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(FieldTypeRequiredException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.response().content("<a>5</a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingXmlResponseField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Fields with the following paths were not found" + " in the payload: [a/b]"));
|
||||
new ResponseFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a/b").description("one"), fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.response().content("<a></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a/b").description("one"), fieldWithPath("a").description("one")))
|
||||
.document(this.operationBuilder.response().content("<a></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessage("Fields with the following paths were not found in the payload: [a/b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedXmlResponseFieldAndMissingXmlResponseField() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(startsWith("The following parts of the payload were not" + " documented:"));
|
||||
this.thrown
|
||||
.expectMessage(endsWith("Fields with the following paths were not found" + " in the payload: [a/b]"));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one")))
|
||||
.document(this.operationBuilder.response().content("<a><c>5</c></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a/b").description("one")))
|
||||
.document(this.operationBuilder.response().content("<a><c>5</c></a>")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).build()))
|
||||
.withMessageStartingWith("The following parts of the payload were not documented:")
|
||||
.withMessageEndingWith("Fields with the following paths were not found in the payload: [a/b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsupportedContent() throws IOException {
|
||||
this.thrown.expect(PayloadHandlingException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Cannot handle text/plain content as it could" + " not be parsed as JSON or XML"));
|
||||
new ResponseFieldsSnippet(Collections.<FieldDescriptor>emptyList()).document(this.operationBuilder.response()
|
||||
.content("Some plain text").header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE).build());
|
||||
assertThatExceptionOfType(PayloadHandlingException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(Collections.<FieldDescriptor>emptyList())
|
||||
.document(this.operationBuilder.response().content("Some plain text")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE).build()))
|
||||
.withMessage("Cannot handle text/plain content as it could not be parsed as JSON or XML");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonOptionalFieldBeneathArrayThatIsSometimesNull() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
startsWith("Fields with the following paths were not found in the payload: " + "[a[].b]"));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.response().content(
|
||||
"{\"a\":[{\"b\": 1,\"c\": 2}, " + "{\"b\": null, \"c\": 2}," + " {\"b\": 1,\"c\": 2}]}")
|
||||
.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.response()
|
||||
.content("{\"a\":[{\"b\": 1,\"c\": 2}, " + "{\"b\": null, \"c\": 2},"
|
||||
+ " {\"b\": 1,\"c\": 2}]}")
|
||||
.build()))
|
||||
.withMessageStartingWith("Fields with the following paths were not found in the payload: [a[].b]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonOptionalFieldBeneathArrayThatIsSometimesAbsent() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
startsWith("Fields with the following paths were not found in the payload: " + "[a[].b]"));
|
||||
new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.response()
|
||||
.content("{\"a\":[{\"b\": 1,\"c\": 2}, " + "{\"c\": 2}, {\"b\": 1,\"c\": 2}]}")
|
||||
.build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new ResponseFieldsSnippet(
|
||||
Arrays.asList(fieldWithPath("a[].b").description("one").type(JsonFieldType.NUMBER),
|
||||
fieldWithPath("a[].c").description("two").type(JsonFieldType.NUMBER)))
|
||||
.document(this.operationBuilder.response()
|
||||
.content("{\"a\":[{\"b\": 1,\"c\": 2}, "
|
||||
+ "{\"c\": 2}, {\"b\": 1,\"c\": 2}]}")
|
||||
.build()))
|
||||
.withMessageStartingWith("Fields with the following paths were not found in the payload: [a[].b]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,14 +22,13 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.restdocs.generate.RestDocumentationGenerator;
|
||||
import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
|
||||
/**
|
||||
@@ -43,35 +42,33 @@ public class PathParametersSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void undocumentedPathParameter() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Path parameters with the following names were" + " not documented: [a]"));
|
||||
new PathParametersSnippet(Collections.<ParameterDescriptor>emptyList()).document(this.operationBuilder
|
||||
.attribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "/{a}/").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new PathParametersSnippet(Collections.<ParameterDescriptor>emptyList())
|
||||
.document(this.operationBuilder
|
||||
.attribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "/{a}/").build()))
|
||||
.withMessage("Path parameters with the following names were not documented: [a]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingPathParameter() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Path parameters with the following names were" + " not found in the request: [a]"));
|
||||
new PathParametersSnippet(Arrays.asList(parameterWithName("a").description("one"))).document(
|
||||
this.operationBuilder.attribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "/").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new PathParametersSnippet(Arrays.asList(parameterWithName("a").description("one")))
|
||||
.document(this.operationBuilder
|
||||
.attribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "/").build()))
|
||||
.withMessage("Path parameters with the following names were not found in the request: [a]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedAndMissingPathParameters() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Path parameters with the following names were"
|
||||
+ " not documented: [b]. Path parameters with the following"
|
||||
+ " names were not found in the request: [a]"));
|
||||
new PathParametersSnippet(Arrays.asList(parameterWithName("a").description("one")))
|
||||
.document(this.operationBuilder
|
||||
.attribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "/{b}").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new PathParametersSnippet(Arrays.asList(parameterWithName("a").description("one")))
|
||||
.document(this.operationBuilder
|
||||
.attribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "/{b}").build()))
|
||||
.withMessage(
|
||||
"Path parameters with the following names were not documented: [b]. Path parameters with the"
|
||||
+ " following names were not found in the request: [a]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -22,13 +22,12 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
|
||||
/**
|
||||
@@ -42,34 +41,29 @@ public class RequestParametersSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void undocumentedParameter() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Request parameters with the following names were" + " not documented: [a]"));
|
||||
new RequestParametersSnippet(Collections.<ParameterDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").param("a", "alpha").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestParametersSnippet(Collections.<ParameterDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").param("a", "alpha").build()))
|
||||
.withMessage("Request parameters with the following names were not documented: [a]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingParameter() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Request parameters with the following names were" + " not found in the request: [a]"));
|
||||
new RequestParametersSnippet(Arrays.asList(parameterWithName("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestParametersSnippet(Arrays.asList(parameterWithName("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build()))
|
||||
.withMessage("Request parameters with the following names were not found in the request: [a]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedAndMissingParameters() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Request parameters with the following names were"
|
||||
+ " not documented: [b]. Request parameters with the following"
|
||||
+ " names were not found in the request: [a]"));
|
||||
new RequestParametersSnippet(Arrays.asList(parameterWithName("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").param("b", "bravo").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestParametersSnippet(Arrays.asList(parameterWithName("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").param("b", "bravo").build()))
|
||||
.withMessage("Request parameters with the following names were not documented: [b]. Request parameters"
|
||||
+ " with the following names were not found in the request: [a]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -22,13 +22,12 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.restdocs.snippet.SnippetException;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.OperationBuilder;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
|
||||
|
||||
/**
|
||||
@@ -42,34 +41,29 @@ public class RequestPartsSnippetFailureTests {
|
||||
@Rule
|
||||
public OperationBuilder operationBuilder = new OperationBuilder(TemplateFormats.asciidoctor());
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void undocumentedPart() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo("Request parts with the following names were" + " not documented: [a]"));
|
||||
new RequestPartsSnippet(Collections.<RequestPartDescriptor>emptyList())
|
||||
.document(this.operationBuilder.request("http://localhost").part("a", "alpha".getBytes()).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestPartsSnippet(Collections.<RequestPartDescriptor>emptyList()).document(
|
||||
this.operationBuilder.request("http://localhost").part("a", "alpha".getBytes()).build()))
|
||||
.withMessage("Request parts with the following names were not documented: [a]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingPart() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Request parts with the following names were" + " not found in the request: [a]"));
|
||||
new RequestPartsSnippet(Arrays.asList(partWithName("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestPartsSnippet(Arrays.asList(partWithName("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").build()))
|
||||
.withMessage("Request parts with the following names were not found in the request: [a]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undocumentedAndMissingParts() throws IOException {
|
||||
this.thrown.expect(SnippetException.class);
|
||||
this.thrown.expectMessage(equalTo(
|
||||
"Request parts with the following names were" + " not documented: [b]. Request parts with the following"
|
||||
+ " names were not found in the request: [a]"));
|
||||
new RequestPartsSnippet(Arrays.asList(partWithName("a").description("one")))
|
||||
.document(this.operationBuilder.request("http://localhost").part("b", "bravo".getBytes()).build());
|
||||
assertThatExceptionOfType(SnippetException.class)
|
||||
.isThrownBy(() -> new RequestPartsSnippet(Arrays.asList(partWithName("a").description("one"))).document(
|
||||
this.operationBuilder.request("http://localhost").part("b", "bravo".getBytes()).build()))
|
||||
.withMessage("Request parts with the following names were not documented: [b]. Request parts with the"
|
||||
+ " following names were not found in the request: [a]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -21,14 +21,12 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link TemplateResourceResolver}.
|
||||
@@ -37,9 +35,6 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||
*/
|
||||
public class StandardTemplateResourceResolverTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final TemplateResourceResolver resolver = new StandardTemplateResourceResolver(
|
||||
TemplateFormats.asciidoctor());
|
||||
|
||||
@@ -101,16 +96,10 @@ public class StandardTemplateResourceResolverTests {
|
||||
|
||||
@Test
|
||||
public void failsIfCustomAndDefaultSnippetsDoNotExist() throws Exception {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage(equalTo("Template named 'test' could not be resolved"));
|
||||
doWithThreadContextClassLoader(this.classLoader, new Callable<Resource>() {
|
||||
|
||||
@Override
|
||||
public Resource call() {
|
||||
return StandardTemplateResourceResolverTests.this.resolver.resolveTemplateResource("test");
|
||||
}
|
||||
|
||||
});
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> doWithThreadContextClassLoader(this.classLoader,
|
||||
() -> StandardTemplateResourceResolverTests.this.resolver.resolveTemplateResource("test")))
|
||||
.withMessage("Template named 'test' could not be resolved");
|
||||
}
|
||||
|
||||
private <T> T doWithThreadContextClassLoader(ClassLoader classLoader, Callable<T> action) throws Exception {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.testfixtures;
|
||||
|
||||
/**
|
||||
* Provides access to {@link System#out System.out} and {@link System#err System.err}
|
||||
* output that has been captured by the {@link OutputCaptureRule}. Can be used to apply
|
||||
* assertions using AssertJ. For example: <pre class="code">
|
||||
* assertThat(output).contains("started"); // Checks all output
|
||||
* assertThat(output.getErr()).contains("failed"); // Only checks System.err
|
||||
* assertThat(output.getOut()).contains("ok"); // Only checks System.out
|
||||
* </pre>
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface CapturedOutput extends CharSequence {
|
||||
|
||||
@Override
|
||||
default int length() {
|
||||
return toString().length();
|
||||
}
|
||||
|
||||
@Override
|
||||
default char charAt(int index) {
|
||||
return toString().charAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
default CharSequence subSequence(int start, int end) {
|
||||
return toString().subSequence(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all content (both {@link System#out System.out} and {@link System#err
|
||||
* System.err}) in the order that it was captured.
|
||||
* @return all captured output
|
||||
*/
|
||||
String getAll();
|
||||
|
||||
/**
|
||||
* Return {@link System#out System.out} content in the order that it was captured.
|
||||
* @return {@link System#out System.out} captured output
|
||||
*/
|
||||
String getOut();
|
||||
|
||||
/**
|
||||
* Return {@link System#err System.err} content in the order that it was captured.
|
||||
* @return {@link System#err System.err} captured output
|
||||
*/
|
||||
String getErr();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -16,139 +16,257 @@
|
||||
|
||||
package org.springframework.restdocs.testfixtures;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.assertj.core.api.HamcrestCondition;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* JUnit {@code @Rule} to capture output from System.out and System.err.
|
||||
* Provides support for capturing {@link System#out System.out} and {@link System#err
|
||||
* System.err}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Sam Brannen
|
||||
* @see OutputCaptureRule
|
||||
*/
|
||||
public class OutputCapture implements TestRule {
|
||||
class OutputCapture implements CapturedOutput {
|
||||
|
||||
private CaptureOutputStream captureOut;
|
||||
private final Deque<SystemCapture> systemCaptures = new ArrayDeque<>();
|
||||
|
||||
private CaptureOutputStream captureErr;
|
||||
|
||||
private ByteArrayOutputStream capturedOutput;
|
||||
|
||||
private List<Matcher<? super String>> matchers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Statement apply(final Statement base, Description description) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
captureOutput();
|
||||
try {
|
||||
base.evaluate();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (!OutputCapture.this.matchers.isEmpty()) {
|
||||
assertThat(getOutputAsString())
|
||||
.is(new HamcrestCondition<>(allOf(OutputCapture.this.matchers)));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
releaseOutput();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void captureOutput() {
|
||||
this.capturedOutput = new ByteArrayOutputStream();
|
||||
this.captureOut = new CaptureOutputStream(System.out, this.capturedOutput);
|
||||
this.captureErr = new CaptureOutputStream(System.err, this.capturedOutput);
|
||||
System.setOut(new PrintStream(this.captureOut));
|
||||
System.setErr(new PrintStream(this.captureErr));
|
||||
}
|
||||
|
||||
private String getOutputAsString() {
|
||||
flush();
|
||||
return this.capturedOutput.toString();
|
||||
}
|
||||
|
||||
private void releaseOutput() {
|
||||
System.setOut(this.captureOut.getOriginal());
|
||||
System.setErr(this.captureErr.getOriginal());
|
||||
this.capturedOutput = null;
|
||||
}
|
||||
|
||||
private void flush() {
|
||||
try {
|
||||
this.captureOut.flush();
|
||||
this.captureErr.flush();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
/**
|
||||
* Push a new system capture session onto the stack.
|
||||
*/
|
||||
final void push() {
|
||||
this.systemCaptures.addLast(new SystemCapture());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the output is matched by the supplied {@code matcher}. Verification is
|
||||
* performed after the test method has executed.
|
||||
* @param matcher the matcher
|
||||
* Pop the last system capture session from the stack.
|
||||
*/
|
||||
public final void expect(Matcher<? super String> matcher) {
|
||||
this.matchers.add(matcher);
|
||||
final void pop() {
|
||||
this.systemCaptures.removeLast().release();
|
||||
}
|
||||
|
||||
private static final class CaptureOutputStream extends OutputStream {
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof CapturedOutput || obj instanceof CharSequence) {
|
||||
return getAll().equals(obj.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private final PrintStream original;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
private final OutputStream copy;
|
||||
@Override
|
||||
public String toString() {
|
||||
return getAll();
|
||||
}
|
||||
|
||||
private CaptureOutputStream(PrintStream original, OutputStream copy) {
|
||||
this.original = original;
|
||||
/**
|
||||
* Return all content (both {@link System#out System.out} and {@link System#err
|
||||
* System.err}) in the order that it was captured.
|
||||
* @return all captured output
|
||||
*/
|
||||
@Override
|
||||
public String getAll() {
|
||||
return get((type) -> true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link System#out System.out} content in the order that it was captured.
|
||||
* @return {@link System#out System.out} captured output
|
||||
*/
|
||||
@Override
|
||||
public String getOut() {
|
||||
return get(Type.OUT::equals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link System#err System.err} content in the order that it was captured.
|
||||
* @return {@link System#err System.err} captured output
|
||||
*/
|
||||
@Override
|
||||
public String getErr() {
|
||||
return get(Type.ERR::equals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current capture session, clearing its captured output.
|
||||
*/
|
||||
void reset() {
|
||||
this.systemCaptures.peek().reset();
|
||||
}
|
||||
|
||||
private String get(Predicate<Type> filter) {
|
||||
Assert.state(!this.systemCaptures.isEmpty(),
|
||||
"No system captures found. Please check your output capture registration.");
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (SystemCapture systemCapture : this.systemCaptures) {
|
||||
systemCapture.append(builder, filter);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A capture session that captures {@link System#out System.out} and {@link System#out
|
||||
* System.err}.
|
||||
*/
|
||||
private static class SystemCapture {
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final PrintStreamCapture out;
|
||||
|
||||
private final PrintStreamCapture err;
|
||||
|
||||
private final List<CapturedString> capturedStrings = new ArrayList<>();
|
||||
|
||||
SystemCapture() {
|
||||
this.out = new PrintStreamCapture(System.out, this::captureOut);
|
||||
this.err = new PrintStreamCapture(System.err, this::captureErr);
|
||||
System.setOut(this.out);
|
||||
System.setErr(this.err);
|
||||
}
|
||||
|
||||
void release() {
|
||||
System.setOut(this.out.getParent());
|
||||
System.setErr(this.err.getParent());
|
||||
}
|
||||
|
||||
private void captureOut(String string) {
|
||||
synchronized (this.monitor) {
|
||||
this.capturedStrings.add(new CapturedString(Type.OUT, string));
|
||||
}
|
||||
}
|
||||
|
||||
private void captureErr(String string) {
|
||||
synchronized (this.monitor) {
|
||||
this.capturedStrings.add(new CapturedString(Type.ERR, string));
|
||||
}
|
||||
}
|
||||
|
||||
void append(StringBuilder builder, Predicate<Type> filter) {
|
||||
synchronized (this.monitor) {
|
||||
for (CapturedString stringCapture : this.capturedStrings) {
|
||||
if (filter.test(stringCapture.getType())) {
|
||||
builder.append(stringCapture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
synchronized (this.monitor) {
|
||||
this.capturedStrings.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link PrintStream} implementation that captures written strings.
|
||||
*/
|
||||
private static class PrintStreamCapture extends PrintStream {
|
||||
|
||||
private final PrintStream parent;
|
||||
|
||||
PrintStreamCapture(PrintStream parent, Consumer<String> copy) {
|
||||
super(new OutputStreamCapture(getSystemStream(parent), copy));
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
PrintStream getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
private static PrintStream getSystemStream(PrintStream printStream) {
|
||||
while (printStream instanceof PrintStreamCapture) {
|
||||
printStream = ((PrintStreamCapture) printStream).getParent();
|
||||
}
|
||||
return printStream;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link OutputStream} implementation that captures written strings.
|
||||
*/
|
||||
private static class OutputStreamCapture extends OutputStream {
|
||||
|
||||
private final PrintStream systemStream;
|
||||
|
||||
private final Consumer<String> copy;
|
||||
|
||||
OutputStreamCapture(PrintStream systemStream, Consumer<String> copy) {
|
||||
this.systemStream = systemStream;
|
||||
this.copy = copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
this.copy.write(b);
|
||||
this.original.write(b);
|
||||
this.original.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
write(new byte[] { (byte) (b & 0xFF) });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
this.copy.write(b, off, len);
|
||||
this.original.write(b, off, len);
|
||||
}
|
||||
|
||||
private PrintStream getOriginal() {
|
||||
return this.original;
|
||||
this.copy.accept(new String(b, off, len));
|
||||
this.systemStream.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
this.copy.flush();
|
||||
this.original.flush();
|
||||
this.systemStream.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A captured string that forms part of the full output.
|
||||
*/
|
||||
private static class CapturedString {
|
||||
|
||||
private final Type type;
|
||||
|
||||
private final String string;
|
||||
|
||||
CapturedString(Type type, String string) {
|
||||
this.type = type;
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Types of content that can be captured.
|
||||
*/
|
||||
private enum Type {
|
||||
|
||||
OUT, ERR
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.testfixtures;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* JUnit {@code @Rule} to capture output from System.out and System.err.
|
||||
* <p>
|
||||
* To use add as a {@link Rule @Rule}:
|
||||
*
|
||||
* <pre class="code">
|
||||
* public class MyTest {
|
||||
*
|
||||
* @Rule
|
||||
* public OutputCaptureRule output = new OutputCaptureRule();
|
||||
*
|
||||
* @Test
|
||||
* public void test() {
|
||||
* assertThat(output).contains("ok");
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class OutputCaptureRule implements TestRule, CapturedOutput {
|
||||
|
||||
private final OutputCapture delegate = new OutputCapture();
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
OutputCaptureRule.this.delegate.push();
|
||||
try {
|
||||
base.evaluate();
|
||||
}
|
||||
finally {
|
||||
OutputCaptureRule.this.delegate.pop();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAll() {
|
||||
return this.delegate.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOut() {
|
||||
return this.delegate.getOut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErr() {
|
||||
return this.delegate.getErr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.delegate.toString();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user