/** * Copyright 2013 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 io.neba.core.mvc; import io.neba.api.annotations.ResourceParam; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ValueMap; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.core.MethodParameter; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletRequest; import static org.apache.sling.api.resource.Resource.RESOURCE_TYPE_NON_EXISTING; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; /** * @author Olaf Otto */ @RunWith(MockitoJUnitRunner.class) public class ResourceParamArgumentResolverTest { @Mock private HttpServletRequest nonSlingRequest; @Mock private SlingHttpServletRequest slingRequest; @Mock private ResourceResolver resolver; @Mock private Resource resource; @Mock private MethodParameter methodParameter; @Mock private ModelAndViewContainer container; @Mock private NativeWebRequest webRequest; @Mock private WebDataBinderFactory factory; @Mock private ResourceParam resourceParam; private Object resolvedArgument; @InjectMocks private ResourceParamArgumentResolver testee; @Before public void setUp() throws Exception { doReturn(this.resourceParam).when(this.methodParameter).getParameterAnnotation(eq(ResourceParam.class)); doReturn(this.slingRequest).when(this.webRequest).getNativeRequest(); doReturn(this.resolver).when(this.slingRequest).getResourceResolver(); doReturn(getClass()).when(this.methodParameter).getParameterType(); } @Test(expected = IllegalStateException.class) public void testHandlingOfUnexpectedRequestType() throws Exception { withNonSlingRequest(); resolveArgument(); } @Test(expected = MissingServletRequestParameterException.class) public void testHandlingOfMissingRequiredResourceParameter() throws Exception { withParameterRequired(); resolveArgument(); } @Test public void testHandlingOfMissingOptionalResourceParameter() throws Exception { resolveArgument(); assertResolvedArgumentIsNull(); } @Test public void testResourceParamAnnotationIsSupported() throws Exception { assertThat(this.testee.supportsParameter(this.methodParameter)).isTrue(); } @Test(expected = UnresolvableResourceException.class) public void testHandlingOfUnresolvableRequiredResource() throws Exception { withParameterRequired(); withResourceParameter("/junit/test/path"); resolveArgument(); } @Test(expected = UnresolvableResourceException.class) public void testHandlingOfNonExistingRequiredResource() throws Exception { withParameterRequired(); withResourceParameter("/junit/test/path"); withResolvedResource(); withResourceTypeNonExisting(); resolveArgument(); } @Test public void testHandlingOfUnresolvableOptionalResource() throws Exception { withResourceParameter("/junit/test/path"); resolveArgument(); verifyResolvedPathIs("/junit/test/path"); assertResolvedArgumentIsNull(); } @Test(expected = MissingAdapterException.class) public void testHandlingOfUnAdaptableRequiredType() throws Exception { withParameterRequired(); withResourceParameter("/junit/test/path"); withResolvedResource(); resolveArgument(); } @Test public void testHandlingOfUnAdaptableOptionalType() throws Exception { withResourceParameter("/junit/test/path"); withResolvedResource(); resolveArgument(); verifyResolvedPathIs("/junit/test/path"); assertResolvedArgumentIsNull(); } @Test public void testResolutionOfResourceParameter() throws Exception { withResourceParameter("/junit/test/path"); withResolvedResource(); withParameterType(Resource.class); resolveArgument(); verifyResolvedPathIs("/junit/test/path"); assertResourceIsResolvedAsArgument(); } @Test public void testResolutionOfNonResourceParameter() throws Exception { withResourceParameter("/junit/test/path"); withResolvedResource(); withParameterType(ValueMap.class); withResourceAdaptingTo(ValueMap.class); resolveArgument(); verifyResolvedPathIs("/junit/test/path"); assertResolvedArgumentIsA(ValueMap.class); } @Test public void testResolverUsesParameterNameOfAnnotationByDefault() throws Exception { withResourceParamValue("parameterName"); withDefaultParameterName("defaultName"); resolveArgument(); verifyResolverLooksUpParameter("parameterName"); } @Test public void testResolverFallsBackToParameterNameIfAnnotationHasNoValue() throws Exception { withResourceParamValue(""); withDefaultParameterName("defaultName"); resolveArgument(); verifyResolverLooksUpParameter("defaultName"); } @Test public void testAppendPathIsIgnoredIfValueIsNull() throws Exception { withResourceParameter(null); withAppendPath("/jcr:content"); resolveArgument(); assertResolvedArgumentIsNull(); } @Test public void testAppendPathIsAddedToNonNullValue() throws Exception { withResourceParameter("/content/path"); withAppendPath("/jcr:content"); withParameterType(Resource.class); withResolvedResource(); resolveArgument(); verifyResolvedPathIs("/content/path/jcr:content"); assertResourceIsResolvedAsArgument(); } @Test public void testAppendPathIsAddedToDefaultValue() throws Exception { withDefaultValue("/default/path"); withAppendPath("/jcr:content"); withParameterType(Resource.class); withResolvedResource(); resolveArgument(); verifyResolvedPathIs("/default/path/jcr:content"); assertResourceIsResolvedAsArgument(); } @Test public void testParametersAreOptionalIfDefaultValueIsProvided() throws Exception { withDefaultValue("/default/value"); withDefaultParameterName("defaultName"); withParameterRequired(); resolveArgument(); assertResolvedArgumentIsNull(); } @Test public void testDefaultValueIsResolvedIfNoRequestParameterIsPresent() throws Exception { withDefaultValue("/default/value"); withDefaultParameterName("defaultName"); withParameterType(Resource.class); withResolvedResource(); resolveArgument(); verifyDefaultResourceIsResolved(); verifyResolvedPathIs("/default/value"); assertResourceIsResolvedAsArgument(); } private void verifyDefaultResourceIsResolved() { String defaultValue = this.resourceParam.defaultValue(); verifyResolvedPathIs(defaultValue); } private void withDefaultValue(String defaultValue) { doReturn(defaultValue).when(this.resourceParam).defaultValue(); } private void withDefaultParameterName(String parameterName) { doReturn(parameterName).when(this.methodParameter).getParameterName(); } private void withAppendPath(String path) { doReturn(path).when(this.resourceParam).append(); } private void verifyResolverLooksUpParameter(String key) { verify(this.slingRequest).getParameter(eq(key)); } private void verifyResolvedPathIs(String path) { verify(this.resolver).resolve(eq(this.slingRequest), eq(path)); } private void withResourceParamValue(String parameterName) { doReturn(parameterName).when(this.resourceParam).value(); } private void assertResolvedArgumentIsNull() { assertThat(this.resolvedArgument).isNull(); } private void assertResolvedArgumentIsA(Class<?> type) { assertThat(this.resolvedArgument).isInstanceOf(type); } private void withResourceAdaptingTo(Class<?> type) { doReturn(mock(type)).when(this.resource).adaptTo(eq(type)); } private void assertResourceIsResolvedAsArgument() { assertThat(this.resolvedArgument).isSameAs(this.resource); } private void withParameterType(Class<?> parameterType) { doReturn(parameterType).when(this.methodParameter).getParameterType(); } private void withResourceParameter(String resourcePath) { doReturn(resourcePath).when(this.slingRequest).getParameter(anyString()); } private void withResolvedResource() { doReturn(this.resource).when(this.resolver).resolve(any(HttpServletRequest.class), anyString()); } private void withParameterRequired() { doReturn(true).when(this.resourceParam).required(); } private void resolveArgument() throws Exception { this.resolvedArgument = testee.resolveArgument(this.methodParameter, this.container, this.webRequest, this.factory); } private void withNonSlingRequest() { doReturn(this.nonSlingRequest).when(this.webRequest).getNativeRequest(); } private void withResourceTypeNonExisting() { doReturn(RESOURCE_TYPE_NON_EXISTING).when(this.resource).getResourceType(); } }