package br.com.caelum.vraptor.jpa.extra; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import javax.persistence.EntityManager; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.MappedSuperclassType; import javax.persistence.metamodel.Metamodel; import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.Type; import javax.servlet.http.HttpServletRequest; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Stubber; 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.converter.LongConverter; import br.com.caelum.vraptor.converter.StringConverter; import br.com.caelum.vraptor.core.Converters; import br.com.caelum.vraptor.events.ControllerFound; import br.com.caelum.vraptor.http.Parameter; import br.com.caelum.vraptor.http.ParameterNameProvider; import br.com.caelum.vraptor.view.FlashScope; public class ParameterLoaderTest { private @Mock EntityManager em; private @Mock HttpServletRequest request; private @Mock ParameterNameProvider provider; private @Mock Result result; private @Mock Converters converters; private @Mock FlashScope flash; private @Mock Metamodel metamodel; private @Mock EntityType entityType; private @Mock Type type; private @Mock SingularAttribute attribute; private @Mock MappedSuperclassType mappedSuperclassType; private ParameterLoader parameterLoader; private ControllerMethod method; private ControllerMethod methodOtherIdName; private ControllerMethod other; private ControllerMethod noId; private ControllerMethod methodWithoutLoad; private ControllerMethod methodMappedSuperClass; private ControllerMethod methodChild; private ControllerMethod methodSon; private ControllerMethod methodGrandSon; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); parameterLoader = new ParameterLoader(em, request, provider, result, converters, flash); method = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("method", Entity.class)); methodWithoutLoad = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("methodWithoutLoad")); methodOtherIdName = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("methodOtherIdName", EntityOtherIdName.class)); other = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("other", OtherEntity.class, String.class)); noId = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("noId", NoIdEntity.class)); methodMappedSuperClass = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("methodMappedSuperClass", MappedSuperClass.class)); methodChild = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("methodChild", Child.class)); methodSon = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("methodSon", Son.class)); methodGrandSon = DefaultControllerMethod.instanceFor(Resource.class, Resource.class.getMethod("methodGrandSon", GrandSon.class)); when(converters.to(Long.class)).thenReturn(new LongConverter()); when(converters.to(String.class)).thenReturn(new StringConverter()); when(em.getMetamodel()).thenReturn(metamodel); when(metamodel.entity(any(Class.class))).thenReturn(entityType); when(entityType.getIdType()).thenReturn(type); when(attribute.getType()).thenReturn(type); } @Test @SuppressWarnings({ "unchecked" }) public void shouldLoadEntityUsingId() throws Exception { Parameter parameter = new Parameter(0, "entity", method.getMethod()); when(provider.parametersFor(method.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("entity.id")).thenReturn("123"); Entity expectedEntity = new Entity(); when(em.find(Entity.class, 123L)).thenReturn(expectedEntity); when(entityType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(method)); verify(request).setAttribute("entity", expectedEntity); } @Test public void shouldLoadEntityUsingOtherIdName() throws Exception { Parameter parameter = new Parameter(0, "entity", methodOtherIdName.getMethod()); when(provider.parametersFor(methodOtherIdName.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("entity.otherIdName")).thenReturn("456"); EntityOtherIdName expectedEntity = new EntityOtherIdName(); when(em.find(EntityOtherIdName.class, 456L)).thenReturn(expectedEntity); when(entityType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("otherIdName"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(methodOtherIdName)); verify(request).setAttribute("entity", expectedEntity); } @Test public void shouldLoadEntityUsingIdOfAnyType() throws Exception { Parameter parameter0 = new Parameter(0, "entity", other.getMethod()); when(provider.parametersFor(other.getMethod())).thenReturn(new Parameter[] { parameter0 }); when(request.getParameter("entity.id")).thenReturn("123"); OtherEntity expectedEntity = new OtherEntity(); when(em.find(OtherEntity.class, "123")).thenReturn(expectedEntity); when(entityType.getDeclaredId(String.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(String.class); parameterLoader.load(new ControllerFound(other)); verify(request).setAttribute("entity", expectedEntity); } @Test @SuppressWarnings({ "unchecked" }) public void shouldLoadMappedSuperClassUsingId() throws Exception { Parameter parameter = new Parameter(0, "mappedSuperClass", methodMappedSuperClass.getMethod()); when(provider.parametersFor(methodMappedSuperClass.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("mappedSuperClass.id")).thenReturn("123"); MappedSuperClass expectedEntity = new MappedSuperClass(); when(em.find(MappedSuperClass.class, 123L)).thenReturn(expectedEntity); when(entityType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(methodMappedSuperClass)); verify(request).setAttribute("mappedSuperClass", expectedEntity); } @Test @SuppressWarnings({ "unchecked" }) public void shouldLoadChildUsingId() throws Exception { Parameter parameter = new Parameter(0, "child", methodChild.getMethod()); when(provider.parametersFor(methodChild.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("child.id")).thenReturn("123"); Child expectedEntity = new Child(); when(em.find(Child.class, 123L)).thenReturn(expectedEntity); when(entityType.getSupertype()).thenReturn(mappedSuperclassType); when(mappedSuperclassType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(methodChild)); verify(request).setAttribute("child", expectedEntity); } @Test @SuppressWarnings({ "unchecked" }) public void shouldLoadSonUsingId() throws Exception { Parameter parameter = new Parameter(0, "son", methodSon.getMethod()); when(provider.parametersFor(methodSon.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("son.id")).thenReturn("123"); Son expectedEntity = new Son(); when(em.find(Son.class, 123L)).thenReturn(expectedEntity); when(entityType.getSupertype()).thenReturn(mappedSuperclassType); when(mappedSuperclassType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(methodSon)); verify(request).setAttribute("son", expectedEntity); } @Test @SuppressWarnings({ "unchecked" }) public void shouldLoadGrandSonUsingId() throws Exception { Parameter parameter = new Parameter(0, "grandSon", methodGrandSon.getMethod()); when(provider.parametersFor(methodGrandSon.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("grandSon.id")).thenReturn("123"); GrandSon expectedEntity = new GrandSon(); when(em.find(GrandSon.class, 123L)).thenReturn(expectedEntity); when(entityType.getSupertype()).thenReturn(mappedSuperclassType); when(mappedSuperclassType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(methodGrandSon)); verify(request).setAttribute("grandSon", expectedEntity); } @Test public void shouldOverrideFlashScopedArgsIfAny() throws Exception { Parameter parameter = new Parameter(0, "entity", method.getMethod()); when(provider.parametersFor(method.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("entity.id")).thenReturn("123"); Object[] args = {new Entity()}; when(entityType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); when(flash.consumeParameters(method)).thenReturn(args); Entity expectedEntity = new Entity(); when(em.find(Entity.class, 123l)).thenReturn(expectedEntity); parameterLoader.load(new ControllerFound(method)); assertThat(args[0], is((Object) expectedEntity)); verify(flash).includeParameters(method, args); } @Test public void shouldSend404WhenNoIdIsSet() throws Exception { Parameter parameter0 = new Parameter(0, "entity", methodOtherIdName.getMethod()); when(provider.parametersFor(method.getMethod())).thenReturn(new Parameter[]{parameter0}); when(request.getParameter("entity.id")).thenReturn(null); when(entityType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(method)); verify(request, never()).setAttribute(eq("entity"), any()); verify(result).notFound(); } @Test public void shouldSend404WhenIdDoesntExist() throws Exception { Parameter parameter = new Parameter(0, "entity", methodOtherIdName.getMethod()); when(provider.parametersFor(method.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("entity.id")).thenReturn("123"); when(em.find(Entity.class, 123l)).thenReturn(null); when(entityType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); parameterLoader.load(new ControllerFound(method)); verify(request, never()).setAttribute(eq("entity"), any()); verify(result).notFound(); } @Test(expected=IllegalArgumentException.class) public void shouldThrowIllegalArgumentIfEntityDoesntHaveId() throws Exception { Parameter parameter = new Parameter(0, "entity", methodOtherIdName.getMethod()); when(provider.parametersFor(noId.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("entity.id")).thenReturn("123"); when(entityType.getIdType()).thenReturn(null); fail().when(request).setAttribute(eq("entity"), any()); fail().when(result).notFound(); parameterLoader.load(new ControllerFound(noId)); } @Test(expected=IllegalArgumentException.class) public void shouldThrowIllegalArgumentIfIdIsNotConvertable() throws Exception { Parameter parameter = new Parameter(0, "entity", methodOtherIdName.getMethod()); when(provider.parametersFor(method.getMethod())).thenReturn(new Parameter[]{parameter}); when(request.getParameter("entity.id")).thenReturn("123"); when(converters.to(Long.class)).thenReturn(null); when(entityType.getDeclaredId(Long.class)).thenReturn(attribute); when(attribute.getName()).thenReturn("id"); when(type.getJavaType()).thenReturn(Long.class); fail().when(request).setAttribute(eq("entity"), any()); fail().when(result).notFound(); parameterLoader.load(new ControllerFound(method)); } static class Entity { @Id Long id; } static class OtherEntity { @Id String id; } static class NoIdEntity { } static class EntityOtherIdName { @Id Long otherIdName; } @MappedSuperclass static class MappedSuperClass { @Id Long id; } static class Child extends MappedSuperClass { } static class Son extends Entity { } static class GrandSon extends Son { } static class Resource { public void method(@Load Entity entity) { } public void other(@Load OtherEntity entity, String ignored) { } public void noId(@Load NoIdEntity entity) { } public void methodOtherIdName(@Load EntityOtherIdName entity) { } public void methodMappedSuperClass(@Load MappedSuperClass mappedSuperClass) { } public void methodChild(@Load Child child) { } public void methodSon(@Load Son son) { } public void methodGrandSon(@Load GrandSon grandSon) { } public void methodWithoutLoad() { } } private Stubber fail() { return doThrow(new AssertionError()); } }