/**
* Copyright (C) 2012-2017 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 ninja.bodyparser;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.NotNull;
import org.hamcrest.CoreMatchers;
import org.joda.time.LocalDateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.multibindings.Multibinder;
import ninja.Context;
import ninja.params.ControllerMethodInvokerTest.Dep;
import ninja.params.ControllerMethodInvokerTest.NeedingInjectionParamParser;
import ninja.params.ParamParser;
import ninja.utils.NinjaMode;
import ninja.utils.NinjaProperties;
import ninja.utils.NinjaPropertiesImpl;
import ninja.validation.ConstraintViolation;
import ninja.validation.IsDate;
import ninja.validation.IsFloat;
import ninja.validation.IsInteger;
import ninja.validation.Validation;
import ninja.validation.ValidationImpl;
/**
*
* @author ra
*/
@RunWith(MockitoJUnitRunner.class)
public class BodyParserEnginePostTest {
@Mock
Context context;
Validation validation;
BodyParserEnginePost bodyParserEnginePost;
@Before
public void setUp() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(NinjaProperties.class).toInstance(new NinjaPropertiesImpl(NinjaMode.test));
Multibinder<ParamParser> parsersBinder = Multibinder.newSetBinder(binder(), ParamParser.class);
parsersBinder.addBinding().to(NeedingInjectionParamParser.class);
}
});
validation = new ValidationImpl();
Mockito.when(this.context.getValidation()).thenReturn(this.validation);
bodyParserEnginePost = injector.getInstance(BodyParserEnginePost.class);
}
@Test
public void testBodyParser() {
// some setup for this method:
String dateString = "2014-10-10";
String dateTimeString = "2014-10-10T20:09:10";
Map<String, String[]> map = new HashMap<>();
map.put("integerPrimitive", new String [] {"1000"});
map.put("integerObject", new String [] {"2000"});
map.put("longPrimitive", new String [] {"3000"});
map.put("longObject", new String [] {"4000"});
map.put("floatPrimitive", new String [] {"1.234"});
map.put("floatObject", new String [] {"2.345"});
map.put("doublePrimitive", new String [] {"3.456"});
map.put("doubleObject", new String [] {"4.567"});
map.put("string", new String [] {"aString"});
map.put("characterPrimitive", new String [] {"a"});
map.put("characterObject", new String [] {"b"});
map.put("date", new String[]{dateString});
map.put("timestamp", new String[]{dateTimeString});
map.put("somethingElseWhatShouldBeSkipped", new String [] {"somethingElseWhatShouldBeSkipped"});
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObject testObject = bodyParserEnginePost.invoke(context, TestObject.class);
// and test:
assertThat(testObject.integerPrimitive, CoreMatchers.equalTo(1000));
assertThat(testObject.integerObject, CoreMatchers.equalTo(2000));
assertThat(testObject.longPrimitive, CoreMatchers.equalTo(3000L));
assertThat(testObject.longObject, CoreMatchers.equalTo(4000L));
assertThat(testObject.floatPrimitive, CoreMatchers.equalTo(1.234F));
assertThat(testObject.floatObject, CoreMatchers.equalTo(2.345F));
assertThat(testObject.doublePrimitive, CoreMatchers.equalTo(3.456D));
assertThat(testObject.doubleObject, CoreMatchers.equalTo(4.567D));
assertThat(testObject.string, equalTo("aString"));
assertThat(testObject.characterPrimitive, equalTo('a'));
assertThat(testObject.characterObject, equalTo('b'));
assertThat(testObject.date, CoreMatchers.equalTo(new LocalDateTime(dateString).toDate()));
assertThat(testObject.timestamp, CoreMatchers.equalTo(new LocalDateTime(dateTimeString).toDate()));
assertFalse(validation.hasViolations());
}
@Test
public void testBodyParserWithValidationErrors() {
// some setup for this method:
Map<String, String[]> map = new HashMap<>();
map.put("integerPrimitive", new String [] {"a"});
map.put("integerObject", new String [] {"b"});
map.put("longPrimitive", new String [] {"c"});
map.put("longObject", new String [] {"d"});
map.put("floatPrimitive", new String [] {"e"});
map.put("floatObject", new String [] {"f"});
map.put("doublePrimitive", new String [] {"g"});
map.put("doubleObject", new String [] {"h"});
map.put("characterPrimitive", new String [] {null});
map.put("characterObject", new String [] {null});
map.put("date", new String[]{"cc"});
map.put("timestamp", new String[]{"dd"});
map.put("somethingElseWhatShouldBeSkipped", new String [] {"somethingElseWhatShouldBeSkipped"});
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObject testObject = bodyParserEnginePost.invoke(context, TestObject.class);
// and test:
assertTrue(validation.hasViolations());
assertViolation("integerPrimitive", IsInteger.KEY);
assertThat(testObject.integerPrimitive, equalTo(0));
assertViolation("integerObject", IsInteger.KEY);
assertNull(testObject.integerObject);
assertViolation("longPrimitive", IsInteger.KEY);
assertThat(testObject.longPrimitive, equalTo(0L));
assertViolation("longObject", IsInteger.KEY);
assertNull(testObject.longObject);
assertViolation("floatPrimitive", IsFloat.KEY);
assertThat(testObject.floatPrimitive, equalTo(0F));
assertViolation("floatObject", IsFloat.KEY);
assertNull(testObject.floatObject);
assertViolation("doublePrimitive", IsFloat.KEY);
assertThat(testObject.doublePrimitive, equalTo(0D));
assertViolation("doubleObject", IsFloat.KEY);
assertNull(testObject.doubleObject);
assertViolation("date", IsDate.KEY);
assertNull(testObject.date);
assertViolation("timestamp", IsDate.KEY);
assertNull(testObject.timestamp);
assertNull(testObject.string);
assertThat(testObject.characterPrimitive, equalTo('\0'));
assertNull(testObject.characterObject);
assertNull(testObject.string);
}
@Test
public void testBodyParserWhenThereIsAnUnsupportedFieldType() {
// some setup for this method:
Map<String, String[]> map = new HashMap<>();
map.put("string", new String [] {"aString"});
map.put("iAmNotSupportedField", new String [] {"iAmNotSupportedField"});
map.put("longs", new String[] {"1", "2"});
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObjectWithUnsupportedFields testObject = bodyParserEnginePost.invoke(context, TestObjectWithUnsupportedFields.class);
// and test:
assertThat(testObject.string, equalTo("aString"));
assertThat(testObject.iAmNotSupportedField, CoreMatchers.equalTo(null));
assertThat(testObject.longs, CoreMatchers.equalTo(null));
}
@Test
public void testBodyParserWithCollectionAndArray() {
Map<String, String[]> map = new HashMap<>();
map.put("integers", new String[] {"1", "2"});
map.put("strings", new String[] {"hello", "world"});
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObjectWithArraysAndCollections testObject = bodyParserEnginePost.invoke(context, TestObjectWithArraysAndCollections.class);
// and test:
assertThat(testObject.integers.length, equalTo(2));
assertThat(testObject.integers[0], equalTo(1));
assertThat(testObject.integers[1], equalTo(2));
assertThat(testObject.strings.size(), equalTo(2));
assertThat(testObject.strings.get(0), equalTo("hello"));
assertThat(testObject.strings.get(1), equalTo("world"));
assertFalse(validation.hasViolations());
}
@Test
public void testBodyParserWithEnumerations() {
// some setup for this method:
Map<String, String[]> map = new HashMap<>();
map.put("enum1", new String[] {MyEnum.VALUE_A.name()});
map.put("enum2", new String[] {new String("value_b")});
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObjectWithEnum testObject = bodyParserEnginePost.invoke(context, TestObjectWithEnum.class);
// and test:
assertThat(testObject.enum1, equalTo(MyEnum.VALUE_A));
assertThat(testObject.enum2, equalTo(MyEnum.VALUE_B));
assertFalse(validation.hasViolations());
}
@Test
public void testBodyParserWithCustomNeedingInjectionParamParser() {
// some setup for this method:
Map<String, String[]> map = new HashMap<>();
map.put("dep", new String[] {"dep1"});
map.put("depArray", new String[] {"depArray1", "depArray2"});
map.put("depList", new String[] {"depList1", "depList2"});
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObjectWithCustomType testObject = bodyParserEnginePost.invoke(context, TestObjectWithCustomType.class);
// and test:
assertThat(testObject.dep, equalTo(new Dep("hello_dep1")));
assertNotNull(testObject.depArray);
assertThat(testObject.depArray.length, equalTo(2));
assertThat(testObject.depArray[0], equalTo(new Dep("hello_depArray1")));
assertThat(testObject.depArray[1], equalTo(new Dep("hello_depArray2")));
assertNotNull(testObject.depList);
assertThat(testObject.depList.size(), equalTo(2));
assertThat(testObject.depList.get(0), equalTo(new Dep("hello_depList1")));
assertThat(testObject.depList.get(1), equalTo(new Dep("hello_depList2")));
assertFalse(validation.hasViolations());
}
@Test
public void testBodyParserWithInnerObjects() {
// some setup for this method:
Map<String, String[]> map = new HashMap<>();
map.put("object1.integerPrimitive", new String [] {"1000"});
map.put("object1.integerObject", new String [] {"2000"});
map.put("object2.integerPrimitive", new String [] {"3000"});
map.put("object2.integerObject", new String [] {"4000"});
Mockito.when(context.getParameter("object1.integerPrimitive")).thenReturn("1000");
Mockito.when(context.getParameter("object1.integerObject")).thenReturn("2000");
Mockito.when(context.getParameter("object2.integerPrimitive")).thenReturn("3000");
Mockito.when(context.getParameter("object2.integerObject")).thenReturn("4000");
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObjectWithInnerObjects testObject = bodyParserEnginePost.invoke(context, TestObjectWithInnerObjects.class);
// and test:
assertNotNull(testObject.object1);
assertThat(testObject.object1.integerPrimitive, equalTo(1000));
assertThat(testObject.object1.integerObject, equalTo(2000));
assertNotNull(testObject.object2);
assertThat(testObject.object2.integerPrimitive, equalTo(3000));
assertThat(testObject.object2.integerObject, equalTo(4000));
assertFalse(validation.hasViolations());
}
@Test
public void testBodyParserWithEmptyInnerObjects() {
// some setup for this method:
Map<String, String[]> map = new HashMap<>();
map.put("object1.integerPrimitive", new String [] {""});
map.put("object1.integerObject", new String [] {""});
map.put("object2.integerPrimitive", new String [] {null});
map.put("object2.integerObject", new String [] {null});
Mockito.when(context.getParameter("object1.integerPrimitive")).thenReturn("");
Mockito.when(context.getParameter("object1.integerObject")).thenReturn("");
Mockito.when(context.getParameter("object2.integerPrimitive")).thenReturn(null);
Mockito.when(context.getParameter("object2.integerObject")).thenReturn(null);
Mockito.when(context.getParameters()).thenReturn(map);
Mockito.when(context.getValidation()).thenReturn(validation);
// do
TestObjectWithInnerObjects testObject = bodyParserEnginePost.invoke(context, TestObjectWithInnerObjects.class);
// and test:
assertNull(testObject.object1);
assertNull(testObject.object2);
// objects should not have been initialized for empty content
assertFalse(validation.hasViolations());
}
private <T> void assertViolation(String fieldName, String violationMessage) {
assertTrue(validation.hasViolation(fieldName));
assertFalse(validation.getViolations().isEmpty());
assertThat(validation.getViolations(fieldName).size(), equalTo(1));
ConstraintViolation violation = validation.getViolations(fieldName).get(0);
assertNotNull(violation);
assertThat(violation.getFieldKey(), equalTo(fieldName));
assertThat(violation.getMessageKey(), equalTo(violationMessage));
}
public static class TestObject {
public int integerPrimitive;
public Integer integerObject;
public long longPrimitive;
public Long longObject;
public float floatPrimitive;
public Float floatObject;
public double doublePrimitive;
public Double doubleObject;
public String string;
public char characterPrimitive;
public Character characterObject;
public Date date;
public Date timestamp;
@NotNull
public Object requiredObject;
}
public static class TestObjectWithUnsupportedFields {
public StringBuffer iAmNotSupportedField;
public String string;
public long[] longs;
}
public static class TestObjectWithArraysAndCollections {
public Integer[] integers;
public List<String> strings;
}
public static enum MyEnum {
VALUE_A, VALUE_B, VALUE_C
}
public static class TestObjectWithEnum {
public MyEnum enum1;
public MyEnum enum2;
}
public static class TestObjectWithCustomType {
public Dep dep;
public Dep[] depArray;
public List<Dep> depList;
}
public static class TestObjectWithInnerObjects {
public TestObject object1;
public TestObject object2;
}
}