package br.com.caelum.vraptor.http;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import br.com.caelum.vraptor.Converter;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.converter.LongConverter;
import br.com.caelum.vraptor.converter.PrimitiveLongConverter;
import br.com.caelum.vraptor.converter.StringConverter;
import br.com.caelum.vraptor.core.Converters;
import br.com.caelum.vraptor.core.SafeResourceBundle;
import br.com.caelum.vraptor.ioc.Container;
import br.com.caelum.vraptor.resource.DefaultResourceMethod;
import br.com.caelum.vraptor.resource.ResourceMethod;
import br.com.caelum.vraptor.util.EmptyBundle;
import br.com.caelum.vraptor.validator.DefaultValidationException;
import br.com.caelum.vraptor.validator.Message;
import com.google.common.collect.ImmutableMap;
public abstract class ParametersProviderTest {
protected @Mock Converters converters;
protected @Mock ParameterNameProvider nameProvider;
protected @Mock HttpServletRequest request;
protected @Mock Container container;
protected ArrayList<Message> errors;
protected ParametersProvider provider;
protected ResourceMethod buyA;
protected ResourceMethod kick;
protected ResourceMethod error;
protected ResourceMethod array;
protected ResourceMethod simple;
protected ResourceMethod list;
protected ResourceMethod listOfObject;
protected ResourceMethod abc;
protected ResourceMethod string;
protected ResourceMethod generic;
protected ResourceMethod primitive;
protected ResourceMethod stringArray;
protected ResourceMethod dependency;
protected ResourceMethod doNothing;
protected abstract ParametersProvider getProvider();
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
this.provider = getProvider();
this.errors = new ArrayList<Message>();
when(converters.existsFor(Long.class)).thenReturn(true);
when(converters.existsFor(long.class)).thenReturn(true);
when(converters.existsFor(String.class)).thenReturn(true);
when(converters.to(Long.class)).thenReturn(new LongConverter());
when(converters.to(long.class)).thenReturn(new PrimitiveLongConverter());
when(converters.to(String.class)).thenReturn(new StringConverter());
when(nameProvider.parameterNamesFor(any(AccessibleObject.class))).thenReturn(new String[0]);
buyA = method("buyA", House.class);
kick = method("kick", AngryCat.class);
error = method("error", WrongCat.class);
array = method("array", Long[].class);
list = method("list", List.class);
listOfObject= method("listOfObject", List.class);
abc = method("abc", ABC.class);
simple = method("simple", Long.class);
string = method("string", String.class);
stringArray = method("stringArray", String[].class);
dependency = method("dependency", Result.class);
primitive = method("primitive", long.class);
doNothing = method("doNothing");
generic = DefaultResourceMethod.instanceFor(Specific.class, Generic.class.getDeclaredMethod("generic", Object.class));
}
protected ResourceMethod method(String methodName, Class<?>... argTypes) throws NoSuchMethodException {
return DefaultResourceMethod.instanceFor(MyResource.class, MyResource.class.getDeclaredMethod(methodName, argTypes));
}
@Test
public void isCapableOfDealingWithStrings() throws Exception {
requestParameterIs(string, "abc", "eureka");
String abc = getParameters(string);
assertThat(abc, is("eureka"));
}
@Test
public void isCapableOfDealingWithStringArrays() throws Exception {
requestParameterIs(stringArray, "abc", "eureka");
String[] abc = getParameters(stringArray);
assertThat(abc, is(new String[] {"eureka"}));
}
@Test
public void isCapableOfDealingWithIndexedStringArrays() throws Exception {
requestParameterIs(stringArray, "abc[0]", "eureka");
String[] abc = getParameters(stringArray);
assertThat(abc, is(new String[] {"eureka"}));
}
@Test
public void isCapableOfDealingWithGenerics() throws Exception {
requestParameterIs(generic, "abc.x", "123");
ABC abc = getParameters(generic);
assertThat(abc.x, is(123l));
}
@Test
public void isCapableOfDealingWithIndexedLists() throws Exception {
requestParameterIs(list, "abc[2]", "1");
List<Long> abc = getParameters(list);
assertThat(abc, hasSize(1));
assertThat(abc, hasItem(1l));
}
@Test
public void isCapableOfDealingWithIndexedListsOfObjects() throws Exception {
requestParameterIs(listOfObject, "abc[2].x", "1");
List<ABC> abc = getParameters(listOfObject);
assertThat(abc, hasSize(1));
assertThat(abc.get(0).x, is(1l));
}
@Test
public void isCapableOfDealingWithLists() throws Exception {
requestParameterIs(list, "abc", "1");
List<Long> abc = getParameters(list);
assertThat(abc, hasSize(1));
assertThat(abc, hasItem(1l));
}
@Test
public void isCapableOfDealingIndexedArraysWithOneElement() throws Exception {
requestParameterIs(array, "abc[2]", "1");
Long[] abc = getParameters(array);
assertThat(abc, is(arrayContaining(1l)));
}
@Test
public void isCapableOfDealingArraysWithOneElement() throws Exception {
requestParameterIs(array, "abc", "1");
Long[] abc = getParameters(array);
assertThat(abc, is(arrayContaining(1l)));
}
@Test
public void isCapableOfDealingArraysWithSeveralElements() throws Exception {
requestParameterIs(array, "abc", "1", "2", "3");
Long[] abc = getParameters(array);
assertThat(abc, is(arrayContaining(1l, 2l, 3l)));
}
@Test
public void isCapableOfDealingWithEmptyParameterForInternalWrapperValue() throws Exception {
requestParameterIs(buyA, "house.cat.id", "guilherme");
House house = getParameters(buyA);
assertThat(house.cat.id, is(equalTo("guilherme")));
}
@Test
public void removeFromTheCollectionIfAnElementIsCreatedWithinACollectionButNoFieldIsSet() throws Exception {
requestParameterIs(buyA, "house.extraCats[1].id", "guilherme");
House house = getParameters(buyA);
assertThat(house.extraCats, hasSize(1));
assertThat(house.extraCats.get(0).id, is(equalTo("guilherme")));
}
@Test
public void removeFromTheCollectionIfAnElementIsCreatedWithinAnArrayButNoFieldIsSet() throws Exception {
requestParameterIs(buyA, "house.ids[1]", "3");
House house = getParameters(buyA);
assertThat(house.ids.length, is(equalTo(1)));
assertThat(house.ids[0], is(equalTo(3L)));
}
@Test
public void removeFromTheCollectionIfAnElementIsCreatedWithinACollectionButNoFieldIsSetAppartFromTheValueItselfNotAChild()
throws Exception {
requestParameterIs(buyA, "house.owners[1]", "guilherme");
House house = getParameters(buyA);
assertThat(house.owners, hasSize(1));
assertThat(house.owners.get(0), is(equalTo("guilherme")));
}
@Test
public void addsValidationMessageWhenSetterFailsWithAValidationException() throws Exception {
requestParameterIs(kick, "angryCat.id", "guilherme");
getParameters(kick);
assertThat(errors.size(), is(greaterThan(0)));
}
@Test(expected=InvalidParameterException.class)
public void throwsExceptionWhenSetterFailsWithOtherException() throws Exception {
requestParameterIs(error, "wrongCat.id", "guilherme");
getParameters(error);
}
@Test
public void returnsASimpleValue() throws Exception {
requestParameterIs(simple, "xyz", "42");
Long xyz = getParameters(simple);
assertThat(xyz, is(42l));
}
@Test
public void addsValidationErrorsOnConvertionErrors() throws Exception {
requestParameterIs(simple, "xyz", "4s2");
getParameters(simple);
assertThat(errors, hasSize(1));
}
@Test
public void returnsNullWhenThereAreNoParameters() throws Exception {
thereAreNoParameters();
Long xyz = getParameters(simple);
assertThat(xyz, is(nullValue()));
}
@Test
public void returnsDependenciesIfContainerCanProvide() throws Exception {
thereAreNoParameters();
Result result = mock(Result.class);
when(container.canProvide(Result.class)).thenReturn(true);
when(container.instanceFor(Result.class)).thenReturn(result);
Result returned = getParameters(dependency);
assertThat(returned, is(result));
}
@Test
public void returnsDependenciesIfRequestCanProvide() throws Exception {
thereAreNoParameters();
when(nameProvider.parameterNamesFor(dependency.getMethod())).thenReturn(new String[] {"result"});
Result result = mock(Result.class);
when(request.getAttribute("result")).thenReturn(result);
Result returned = getParameters(dependency);
assertThat(returned, is(result));
}
@Test
public void ignoresPopulationIfIfRequestCanProvide() throws Exception {
requestParameterIs(abc, "abc.x", "1");
ABC expected = new ABC();
expected.setX(2l);
when(request.getAttribute("abc")).thenReturn(expected);
ABC returned = getParameters(abc);
assertThat(returned.getX(), is(2l));
}
@Test
public void doesntReturnDependenciesIfItIsNotAnInterface() throws Exception {
thereAreNoParameters();
ABC result = mock(ABC.class);
when(container.canProvide(ABC.class)).thenReturn(true);
when(container.instanceFor(ABC.class)).thenReturn(result);
ABC returned = getParameters(abc);
assertThat(returned, is(not(result)));
}
@Test
public void returnsZeroForAPrimitiveWhenThereAreNoParameters() throws Exception {
thereAreNoParameters();
Long xyz = getParameters(primitive);
assertThat(xyz, is(0l));
}
@Test
public void continuesToFillObjectIfItIsConvertable() throws Exception {
when(request.getParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("abc", "abc.x")));
ImmutableMap<String, String[]> params = ImmutableMap.of("abc", new String[] {""}, "abc.x", new String[] {"3"});
when(request.getParameterMap()).thenReturn(params);
when(request.getParameterValues("abc")).thenReturn(params.get("abc"));
when(request.getParameterValues("abc.x")).thenReturn(params.get("abc.x"));
when(nameProvider.parameterNamesFor(any(Method.class))).thenReturn(new String[]{"abc"});
when(converters.existsFor(ABC.class)).thenReturn(true);
when(converters.to(ABC.class)).thenReturn(new Converter<ABC>() {
public ABC convert(String value, Class<? extends ABC> type, ResourceBundle bundle) {
return new ABC();
}
});
ABC returned = getParameters(abc);
assertThat(returned.x, is(3l));
}
@Test
public void returnsAnEmptyObjectArrayForZeroArityMethods() throws Exception {
thereAreNoParameters();
Object[] params = provider.getParametersFor(doNothing, errors, null);
assertArrayEquals(new Object[] {}, params);
}
@Test
public void returnsNullWhenInstantiatingAListForWhichThereAreNoParameters() throws Exception {
thereAreNoParameters();
Object[] params = provider.getParametersFor(list, errors, null);
assertArrayEquals(new Object[] {null}, params);
}
protected void thereAreNoParameters() {
when(request.getParameterNames()).thenReturn(Collections.enumeration(Collections.<String>emptySet()));
when(request.getParameterMap()).thenReturn(Collections.<String, String[]>emptyMap());
when(nameProvider.parameterNamesFor(any(Method.class))).thenReturn(new String[]{"any"});
}
protected void requestParameterIs(ResourceMethod method, String paramName, String... values) {
String methodName = paramName.replaceAll("[\\.\\[].*", "");
when(request.getParameterValues(paramName)).thenReturn(values);
String[] values1 = { paramName };
when(request.getParameterNames()).thenReturn(Collections.enumeration(Arrays.asList(values1)));
when(nameProvider.parameterNamesFor(method.getMethod())).thenReturn(new String[]{methodName});
when(request.getParameterMap()).thenReturn(Collections.singletonMap(paramName, values));
}
@SuppressWarnings("unchecked")
protected <T> T getParameters(ResourceMethod method) {
return (T) provider.getParametersFor(method, errors, new SafeResourceBundle(new EmptyBundle()))[0];
}
protected static class MyResource {
public MyResource() {
}
void buyA(House house) {
}
void kick(AngryCat angryCat) {
}
void error(WrongCat wrongCat) {
}
void array(Long[] abc) {
}
void list(List<Long> abc) {
}
void listOfObject(List<ABC> abc) {
}
void set(Set<Long> abc) {
}
void setOfObject(Set<ABC> abc) {
}
void abc(ABC abc) {
}
void simple(Long xyz) {
}
void string(String abc) {
}
void stringArray(String[] abc) {
}
void primitive(long xyz) {
}
void dependency(Result result) {
}
void doNothing() {
}
}
static class Generic<T> {
void generic(T t) {
}
}
static class Specific extends Generic<ABC> {
}
public static class Cat {
private String id;
private Long lols;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setLols(Long lols) {
this.lols = lols;
}
public Long getLols() {
return lols;
}
}
public static class House {
private Cat cat;
public void setCat(Cat cat) {
this.cat = cat;
}
public Cat getCat() {
return cat;
}
public void setExtraCats(List<Cat> extraCats) {
this.extraCats = extraCats;
}
public List<Cat> getExtraCats() {
return extraCats;
}
public void setIds(Long[] ids) {
this.ids = ids;
}
private List<String> owners;
public Long[] getIds() {
return ids;
}
public void setOwners(List<String> owners) {
this.owners = owners;
}
public List<String> getOwners() {
return owners;
}
private List<Cat> extraCats;
private Long[] ids;
}
public static class ABC {
private Long x;
public Long getX() {
return x;
}
public void setX(Long x) {
this.x = x;
}
}
public static class AngryCat {
public void setId(String id) {
throw new DefaultValidationException("AngryCat Exception");
}
public String getId() {
throw new DefaultValidationException("AngryCat Exception");
}
}
public static class WrongCat {
public void setId(String id) {
throw new IllegalArgumentException("AngryCat Exception"); //it isn't a ValidationException
}
public String getId() {
throw new IllegalArgumentException("AngryCat Exception"); //it isn't a ValidationException
}
}
}