diff --git a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc index 8cb02054..04a1b48e 100644 --- a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc +++ b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc @@ -109,6 +109,7 @@ the name is equal to any of the given header names. response where the name matches any of the given regular expression patterns. + [[customizing-requests-and-responses-preprocessors-replace-patterns]] ==== Replacing patterns @@ -118,6 +119,14 @@ replaced. +[[customizing-requests-and-responses-preprocessors-modify-request-parameters]] +==== Modifying request parameters + +`modifyParameters` on `Preprocessors` can be used to add, set, and remove request +parameters. + + + [[customizing-requests-and-responses-preprocessors-modify-uris]] ==== Modifying URIs diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequestFactory.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequestFactory.java index c105fd75..961987b5 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequestFactory.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/OperationRequestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2016 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. @@ -72,7 +72,7 @@ public class OperationRequestFactory { * @param original The original request * @param newHeaders The new headers * - * @return The new request with the new content + * @return The new request with the new headers */ public OperationRequest createFrom(OperationRequest original, HttpHeaders newHeaders) { @@ -81,6 +81,22 @@ public class OperationRequestFactory { original.getParts()); } + /** + * Creates a new {@code OperationRequest} based on the given {@code original} but with + * the given {@code newParameters}. + * + * @param original The original request + * @param newParameters The new parameters + * + * @return The new request with the new parameters + */ + public OperationRequest createFrom(OperationRequest original, + Parameters newParameters) { + return new StandardOperationRequest(original.getUri(), original.getMethod(), + original.getContent(), original.getHeaders(), newParameters, + original.getParts()); + } + private HttpHeaders augmentHeaders(HttpHeaders originalHeaders, URI uri, byte[] content) { return new HttpHeadersHelper(originalHeaders) diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/ParametersModifyingOperationPreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/ParametersModifyingOperationPreprocessor.java new file mode 100644 index 00000000..5006c73e --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/ParametersModifyingOperationPreprocessor.java @@ -0,0 +1,181 @@ +/* + * Copyright 2012-2016 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 java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.restdocs.operation.OperationRequest; +import org.springframework.restdocs.operation.OperationRequestFactory; +import org.springframework.restdocs.operation.Parameters; +import org.springframework.util.Assert; + +/** + * An {@link OperationPreprocessor} that can be used to modify a request's + * {@link OperationRequest#getParameters()} by adding, setting, and removing parameters. + * + * @author Andy Wilkinson + * @since 1.1.0 + */ +public final class ParametersModifyingOperationPreprocessor + extends OperationPreprocessorAdapter { + + private final OperationRequestFactory requestFactory = new OperationRequestFactory(); + + private final List modifications = new ArrayList<>(); + + @Override + public OperationRequest preprocess(OperationRequest request) { + Parameters parameters = new Parameters(); + parameters.putAll(request.getParameters()); + for (Modification modification : this.modifications) { + modification.apply(parameters); + } + return this.requestFactory.createFrom(request, parameters); + } + + /** + * Adds a parameter with the given {@code name} and {@code value}. + * + * @param name the name + * @param value the value + * @return {@code this} + */ + public ParametersModifyingOperationPreprocessor add(String name, String value) { + this.modifications.add(new AddParameterModification(name, value)); + return this; + } + + /** + * Sets the parameter with the given {@code name} to have the given {@code values}. + * + * @param name the name + * @param values the values + * @return {@code this} + */ + public ParametersModifyingOperationPreprocessor set(String name, String... values) { + Assert.notEmpty(values, "At least one value must be provided"); + this.modifications.add(new SetParameterModification(name, Arrays.asList(values))); + return this; + } + + /** + * Removes the parameter with the given {@code name}. + * + * @param name the name of the parameter + * @return {@code this} + */ + public ParametersModifyingOperationPreprocessor remove(String name) { + this.modifications.add(new RemoveParameterModification(name)); + return this; + } + + /** + * Removes the given {@code value} from the parameter with the given {@code name}. + * + * @param name the name + * @param value the value + * @return {@code this} + */ + public ParametersModifyingOperationPreprocessor remove(String name, String value) { + this.modifications.add(new RemoveValueParameterModification(name, value)); + return this; + } + + private interface Modification { + + void apply(Parameters parameters); + + } + + private static final class AddParameterModification implements Modification { + + private final String name; + + private final String value; + + private AddParameterModification(String name, String value) { + this.name = name; + this.value = value; + } + + @Override + public void apply(Parameters parameters) { + parameters.add(this.name, this.value); + } + + } + + private static final class SetParameterModification implements Modification { + + private final String name; + + private final List values; + + private SetParameterModification(String name, List values) { + this.name = name; + this.values = values; + } + + @Override + public void apply(Parameters parameters) { + parameters.put(this.name, this.values); + } + + } + + private static final class RemoveParameterModification implements Modification { + + private final String name; + + private RemoveParameterModification(String name) { + this.name = name; + } + + @Override + public void apply(Parameters parameters) { + parameters.remove(this.name); + } + + } + + private static final class RemoveValueParameterModification implements Modification { + + private final String name; + + private final String value; + + private RemoveValueParameterModification(String name, String value) { + this.name = name; + this.value = value; + } + + @Override + public void apply(Parameters parameters) { + List values = parameters.get(this.name); + if (values != null) { + values.remove(this.value); + if (values.isEmpty()) { + parameters.remove(this.name); + } + } + } + + } + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java index d600407a..23a31037 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java @@ -127,7 +127,7 @@ public final class Preprocessors { /** * Returns an {@code OperationPreprocessor} that will modify the content of the - * request or response by replacing occurences of the given {@code pattern} with the + * request or response by replacing occurrences of the given {@code pattern} with the * given {@code replacement}. * * @param pattern the pattern @@ -140,4 +140,15 @@ public final class Preprocessors { new PatternReplacingContentModifier(pattern, replacement)); } + /** + * Returns a {@code ParametersModifyingOperationPreprocessor} that can then be + * configured to modify the parameters of the request. + * + * @return the preprocessor + * @since 1.1.0 + */ + public static ParametersModifyingOperationPreprocessor modifyParameters() { + return new ParametersModifyingOperationPreprocessor(); + } + } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/ParametersModifyingOperationPreprocessorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/ParametersModifyingOperationPreprocessorTests.java new file mode 100644 index 00000000..4d8035f3 --- /dev/null +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/ParametersModifyingOperationPreprocessorTests.java @@ -0,0 +1,136 @@ +/* + * Copyright 2012-2016 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 java.net.URI; +import java.util.Collections; + +import org.junit.Test; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.restdocs.operation.OperationRequest; +import org.springframework.restdocs.operation.OperationRequestFactory; +import org.springframework.restdocs.operation.OperationRequestPart; +import org.springframework.restdocs.operation.Parameters; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasEntry; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link ParametersModifyingOperationPreprocessor}. + * + * @author Andy Wilkinson + */ +public class ParametersModifyingOperationPreprocessorTests { + + private final ParametersModifyingOperationPreprocessor preprocessor = new ParametersModifyingOperationPreprocessor(); + + @Test + public void addNewParameter() { + Parameters parameters = new Parameters(); + assertThat(this.preprocessor.add("a", "alpha") + .preprocess(createRequest(parameters)).getParameters(), + hasEntry(equalTo("a"), contains("alpha"))); + } + + @Test + public void addValueToExistingParameter() { + Parameters parameters = new Parameters(); + parameters.add("a", "apple"); + assertThat( + this.preprocessor.add("a", "alpha").preprocess(createRequest(parameters)) + .getParameters(), + hasEntry(equalTo("a"), contains("apple", "alpha"))); + } + + @Test + public void setNewParameter() { + Parameters parameters = new Parameters(); + assertThat( + this.preprocessor.set("a", "alpha", "avocado") + .preprocess(createRequest(parameters)).getParameters(), + hasEntry(equalTo("a"), contains("alpha", "avocado"))); + } + + @Test + public void setExistingParameter() { + Parameters parameters = new Parameters(); + parameters.add("a", "apple"); + assertThat( + this.preprocessor.set("a", "alpha", "avocado") + .preprocess(createRequest(parameters)).getParameters(), + hasEntry(equalTo("a"), contains("alpha", "avocado"))); + } + + @Test + public void removeNonExistentParameter() { + Parameters parameters = new Parameters(); + assertThat(this.preprocessor.remove("a").preprocess(createRequest(parameters)) + .getParameters().size(), is(equalTo(0))); + } + + @Test + public void removeParameter() { + Parameters parameters = new Parameters(); + parameters.add("a", "apple"); + assertThat( + this.preprocessor.set("a", "alpha", "avocado") + .preprocess(createRequest(parameters)).getParameters(), + hasEntry(equalTo("a"), contains("alpha", "avocado"))); + } + + @Test + public void removeParameterValueForNonExistentParameter() { + Parameters parameters = new Parameters(); + assertThat( + this.preprocessor.remove("a", "apple") + .preprocess(createRequest(parameters)).getParameters().size(), + is(equalTo(0))); + } + + @Test + public void removeParameterValueWithMultipleValues() { + Parameters parameters = new Parameters(); + parameters.add("a", "apple"); + parameters.add("a", "alpha"); + assertThat( + this.preprocessor.remove("a", "apple") + .preprocess(createRequest(parameters)).getParameters(), + hasEntry(equalTo("a"), contains("alpha"))); + } + + @Test + public void removeParameterValueWithSingleValueRemovesEntryEntirely() { + Parameters parameters = new Parameters(); + parameters.add("a", "apple"); + assertThat( + this.preprocessor.remove("a", "apple") + .preprocess(createRequest(parameters)).getParameters().size(), + is(equalTo(0))); + } + + private OperationRequest createRequest(Parameters parameters) { + return new OperationRequestFactory().create(URI.create("http://localhost:8080"), + HttpMethod.GET, new byte[0], new HttpHeaders(), parameters, + Collections.emptyList()); + } + +}