/*** * Copyright (c) 2009 Caelum - www.caelum.com.br/opensource * All rights reserved. * * 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 br.com.caelum.vraptor.view; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.lang.reflect.Method; import java.util.Collections; import javax.servlet.RequestDispatcher; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import br.com.caelum.vraptor.Get; import br.com.caelum.vraptor.Post; import br.com.caelum.vraptor.Result; import br.com.caelum.vraptor.controller.ControllerMethod; import br.com.caelum.vraptor.controller.DefaultControllerMethod; import br.com.caelum.vraptor.core.MethodInfo; import br.com.caelum.vraptor.http.MutableRequest; import br.com.caelum.vraptor.http.MutableResponse; import br.com.caelum.vraptor.http.ParanamerNameProvider; import br.com.caelum.vraptor.http.route.Router; import br.com.caelum.vraptor.interceptor.TypeNameExtractor; import br.com.caelum.vraptor.ioc.Container; import br.com.caelum.vraptor.proxy.JavassistProxifier; import br.com.caelum.vraptor.proxy.Proxifier; import br.com.caelum.vraptor.validator.Message; import br.com.caelum.vraptor.validator.ValidationException; public class DefaultLogicResultTest { @Rule public ExpectedException exception = ExpectedException.none(); private LogicResult logicResult; private @Mock Router router; private @Mock MutableResponse response; private @Mock MutableRequest request; private @Mock Container container; private @Mock PathResolver resolver; private @Mock TypeNameExtractor extractor; private @Mock RequestDispatcher dispatcher; private @Mock FlashScope flash; private Proxifier proxifier; private MethodInfo methodInfo; public static class MyComponent { int calls = 0; public void base() { calls++; } public void withParameter(String a) { } @Post public void annotated() { } @Get public void annotatedWithGet() { } public String returnsValue() { return "A value"; } public void throwsValidationException() { throw new ValidationException(Collections.<Message>emptyList()); } } @Before public void setup() { MockitoAnnotations.initMocks(this); proxifier = new JavassistProxifier(); methodInfo = new MethodInfo(new ParanamerNameProvider()); this.logicResult = new DefaultLogicResult(proxifier, router, request, response, container, resolver, extractor, flash, methodInfo); } @Test public void shouldIncludeReturnValueOnForward() throws Exception { givenDispatcherWillBeReturnedWhenRequested(); when(extractor.nameFor(String.class)).thenReturn("string"); logicResult.forwardTo(MyComponent.class).returnsValue(); verify(dispatcher).forward(request, response); verify(request).setAttribute("string", "A value"); } @Test public void shouldExecuteTheLogicAndRedirectToItsViewOnForward() throws Exception { final MyComponent component = givenDispatcherWillBeReturnedWhenRequested(); assertThat(component.calls, is(0)); logicResult.forwardTo(MyComponent.class).base(); assertThat(component.calls, is(1)); verify(dispatcher).forward(request, response); } private MyComponent givenDispatcherWillBeReturnedWhenRequested() { final MyComponent component = new MyComponent(); when(container.instanceFor(MyComponent.class)).thenReturn(component); when(resolver.pathFor(any(ControllerMethod.class))).thenReturn("Abc123"); when(request.getRequestDispatcher("Abc123")).thenReturn(dispatcher); return component; } @Test public void shouldForwardToMethodsDefaultViewWhenResponseIsNotCommited() throws Exception { givenDispatcherWillBeReturnedWhenRequested(); when(response.isCommitted()).thenReturn(false); logicResult.forwardTo(MyComponent.class).base(); verify(dispatcher).forward(request, response); } @Test public void shouldNotForwardToMethodsDefaultViewWhenResponseIsCommited() throws Exception { givenDispatcherWillBeReturnedWhenRequested(); when(response.isCommitted()).thenReturn(true); logicResult.forwardTo(MyComponent.class).base(); verify(dispatcher, never()).forward(request, response); } @Test public void shouldPutParametersOnFlashScopeOnRedirect() throws Exception { logicResult.redirectTo(MyComponent.class).withParameter("a"); verify(flash).includeParameters(any(ControllerMethod.class), eq(new Object[] {"a"})); } @Test public void shouldNotPutParametersOnFlashScopeOnRedirectIfThereAreNoParameters() throws Exception { logicResult.redirectTo(MyComponent.class).base(); verify(flash, never()).includeParameters(any(ControllerMethod.class), any(Object[].class)); } @Test public void clientRedirectingWillRedirectToTranslatedUrl() throws NoSuchMethodException, IOException { final String url = "custom_url"; when(request.getContextPath()).thenReturn("/context"); when(router.urlFor(MyComponent.class, MyComponent.class.getDeclaredMethod("base"))).thenReturn(url); logicResult.redirectTo(MyComponent.class).base(); verify(response).sendRedirect("/context" + url); } @Test public void canRedirectWhenLogicMethodIsNotAnnotatedWithHttpMethods() throws Exception { logicResult.redirectTo(MyComponent.class).base(); verify(response).sendRedirect(any(String.class)); } @Test public void canRedirectWhenLogicMethodIsAnnotatedWithHttpGetMethod() throws Exception { logicResult.redirectTo(MyComponent.class).annotatedWithGet(); verify(response).sendRedirect(any(String.class)); } @Test public void cannotRedirectWhenLogicMethodIsAnnotatedWithAnyHttpMethodButGet() throws Exception { try { logicResult.redirectTo(MyComponent.class).annotated(); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { verify(response, never()).sendRedirect(any(String.class)); } } @Test public void shouldNotWrapValidationExceptionWhenForwarding() throws Exception { exception.expect(ValidationException.class); givenDispatcherWillBeReturnedWhenRequested(); when(response.isCommitted()).thenReturn(true); logicResult.forwardTo(MyComponent.class).throwsValidationException(); } static class TheComponent { private Result result; public TheComponent() { } public TheComponent(Result result) { this.result = result; } public void method() { result.use(Results.page()).defaultView(); } } /** * @bug #337 */ @Test public void shouldForwardToTheRightDefaultValue() throws Exception { Result result = mock(Result.class); PageResult pageResult = new DefaultPageResult(request, response, methodInfo, resolver, proxifier); when(result.use(PageResult.class)).thenReturn(pageResult); when(container.instanceFor(TheComponent.class)).thenReturn(new TheComponent(result)); when(resolver.pathFor(argThat(sameMethodAs(TheComponent.class.getDeclaredMethod("method"))))).thenReturn("controlled!"); when(request.getRequestDispatcher(anyString())).thenThrow(new AssertionError("should have called with the right method!")); doReturn(dispatcher).when(request).getRequestDispatcher("controlled!"); methodInfo.setControllerMethod(DefaultControllerMethod.instanceFor(MyComponent.class, MyComponent.class.getDeclaredMethod("base"))); logicResult.forwardTo(TheComponent.class).method(); } private TypeSafeMatcher<ControllerMethod> sameMethodAs(final Method method) { return new TypeSafeMatcher<ControllerMethod>() { @Override public void describeTo(Description description) { } @Override protected boolean matchesSafely(ControllerMethod item) { return item.getMethod().equals(method); } @Override protected void describeMismatchSafely(ControllerMethod item, Description mismatchDescription) { } }; } }