/*
* Copyright 2002-2006 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 org.springframework.web.portlet.mvc;
import java.beans.PropertyEditorSupport;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;
import junit.framework.TestCase;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.mock.web.portlet.MockActionRequest;
import org.springframework.mock.web.portlet.MockActionResponse;
import org.springframework.mock.web.portlet.MockRenderRequest;
import org.springframework.mock.web.portlet.MockRenderResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.bind.PortletRequestDataBinder;
import org.springframework.web.portlet.handler.PortletSessionRequiredException;
/**
* @author Mark Fisher
*/
public class CommandControllerTests extends TestCase {
private static final String ERRORS_KEY = "errors";
public void testRenderRequestWithNoParams() throws Exception {
TestController tc = new TestController();
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
request.setContextPath("test");
ModelAndView mav = tc.handleRenderRequest(request, response);
assertEquals("test-view", mav.getViewName());
assertNotNull(mav.getModel().get(tc.getCommandName()));
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertNotNull(errors);
assertEquals("There should be no errors", 0, errors.getErrorCount());
}
public void testRenderRequestWithParams() throws Exception {
TestController tc = new TestController();
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
String name = "test";
int age = 30;
request.addParameter("name", name);
request.addParameter("age", "" + age);
request.setContextPath("test");
ModelAndView mav = tc.handleRenderRequest(request, response);
assertEquals("test-view", mav.getViewName());
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertEquals("Name should be bound", name, command.getName());
assertEquals("Age should be bound", age, command.getAge());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertNotNull(errors);
assertEquals("There should be no errors", 0, errors.getErrorCount());
}
public void testRenderRequestWithMismatch() throws Exception {
TestController tc = new TestController();
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
String name = "test";
request.addParameter("name", name);
request.addParameter("age", "zzz");
request.setContextPath("test");
ModelAndView mav = tc.handleRenderRequest(request, response);
assertEquals("test-view", mav.getViewName());
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertNotNull(command);
assertEquals("Name should be bound", name, command.getName());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be 1 error", 1, errors.getErrorCount());
assertNotNull(errors.getFieldError("age"));
assertEquals("typeMismatch", errors.getFieldError("age").getCode());
}
public void testRenderWhenMinimizedReturnsNull() throws Exception {
TestController tc = new TestController();
assertFalse(tc.isRenderWhenMinimized());
MockRenderRequest request = new MockRenderRequest();
request.setWindowState(WindowState.MINIMIZED);
MockRenderResponse response = new MockRenderResponse();
ModelAndView mav = tc.handleRenderRequest(request, response);
assertNull("ModelAndView should be null", mav);
}
public void testAllowRenderWhenMinimized() throws Exception {
TestController tc = new TestController();
tc.setRenderWhenMinimized(true);
MockRenderRequest request = new MockRenderRequest();
request.setWindowState(WindowState.MINIMIZED);
request.setContextPath("test");
MockRenderResponse response = new MockRenderResponse();
ModelAndView mav = tc.handleRenderRequest(request, response);
assertNotNull("ModelAndView should not be null", mav);
assertEquals("test-view", mav.getViewName());
assertNotNull(mav.getModel().get(tc.getCommandName()));
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be no errors", 0, errors.getErrorCount());
}
public void testRequiresSessionWithoutSession() throws Exception {
TestController tc = new TestController();
tc.setRequireSession(true);
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
try {
tc.handleRenderRequest(request, response);
fail("Should have thrown PortletSessionRequiredException");
}
catch (PortletSessionRequiredException ex) {
// expected
}
}
public void testRequiresSessionWithSession() throws Exception {
TestController tc = new TestController();
tc.setRequireSession(true);
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
// create the session
request.getPortletSession(true);
try {
tc.handleRenderRequest(request, response);
}
catch (PortletSessionRequiredException ex) {
fail("Should not have thrown PortletSessionRequiredException");
}
}
public void testRenderRequestWithoutCacheSetting() throws Exception {
TestController tc = new TestController();
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
tc.handleRenderRequest(request, response);
String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE);
assertNull("Expiration-cache should be null", cacheProperty);
}
public void testRenderRequestWithNegativeCacheSetting() throws Exception {
TestController tc = new TestController();
tc.setCacheSeconds(-99);
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
tc.handleRenderRequest(request, response);
String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE);
assertNull("Expiration-cache should be null", cacheProperty);
}
public void testRenderRequestWithZeroCacheSetting() throws Exception {
TestController tc = new TestController();
tc.setCacheSeconds(0);
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
tc.handleRenderRequest(request, response);
String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE);
assertEquals("Expiration-cache should be set to 0 seconds", "0", cacheProperty);
}
public void testRenderRequestWithPositiveCacheSetting() throws Exception {
TestController tc = new TestController();
tc.setCacheSeconds(30);
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
tc.handleRenderRequest(request, response);
String cacheProperty = response.getProperty(RenderResponse.EXPIRATION_CACHE);
assertEquals("Expiration-cache should be set to 30 seconds", "30", cacheProperty);
}
public void testActionRequest() throws Exception {
TestController tc = new TestController();
MockActionRequest request = new MockActionRequest();
MockActionResponse response = new MockActionResponse();
tc.handleActionRequest(request, response);
TestBean command = (TestBean)request.getPortletSession().getAttribute(tc.getRenderCommandSessionAttributeName());
assertTrue(command.isJedi());
}
public void testSuppressBinding() throws Exception {
TestController tc = new TestController() {
protected boolean suppressBinding(PortletRequest request) {
return true;
}
};
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
String name = "test";
int age = 30;
request.addParameter("name", name);
request.addParameter("age", "" + age);
request.setContextPath("test");
ModelAndView mav = tc.handleRenderRequest(request, response);
assertEquals("test-view", mav.getViewName());
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertNotNull(command);
assertTrue("Name should not have been bound", name != command.getName());
assertTrue("Age should not have been bound", age != command.getAge());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be no errors", 0, errors.getErrorCount());
}
public void testWithCustomDateEditor() throws Exception {
final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
TestController tc = new TestController() {
protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
};
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
String name = "test";
int age = 30;
request.addParameter("name", name);
request.addParameter("age", "" + age);
String dateString = "07-03-2006";
Date expectedDate = dateFormat.parse(dateString);
request.addParameter("date", dateString);
ModelAndView mav = tc.handleRenderRequest(request, response);
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertEquals(name, command.getName());
assertEquals(age, command.getAge());
assertEquals(expectedDate, command.getDate());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be no errors", 0, errors.getErrorCount());
}
public void testWithCustomDateEditorEmptyNotAllowed() throws Exception {
final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
TestController tc = new TestController() {
protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
};
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
String name = "test";
int age = 30;
request.addParameter("name", name);
request.addParameter("age", "" + age);
String emptyString = "";
request.addParameter("date", emptyString);
ModelAndView mav = tc.handleRenderRequest(request, response);
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertEquals(name, command.getName());
assertEquals(age, command.getAge());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be 1 error", 1, errors.getErrorCount());
assertNotNull(errors.getFieldError("date"));
assertEquals("typeMismatch", errors.getFieldError("date").getCode());
assertEquals(emptyString, errors.getFieldError("date").getRejectedValue());
}
public void testWithCustomDateEditorEmptyAllowed() throws Exception {
final DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
TestController tc = new TestController() {
protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
};
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
String name = "test";
int age = 30;
request.addParameter("name", name);
request.addParameter("age", "" + age);
String dateString = "";
request.addParameter("date", dateString);
ModelAndView mav = tc.handleRenderRequest(request, response);
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertEquals(name, command.getName());
assertEquals(age, command.getAge());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be 0 errors", 0, errors.getErrorCount());
assertNull("date should be null", command.getDate());
}
public void testNestedBindingWithPropertyEditor() throws Exception {
TestController tc = new TestController() {
protected void initBinder(PortletRequest request, PortletRequestDataBinder binder) {
binder.registerCustomEditor(ITestBean.class, new PropertyEditorSupport() {
public void setAsText(String text) throws IllegalArgumentException {
setValue(new TestBean(text));
}
});
}
};
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
String name = "test";
String spouseName = "testSpouse";
int age = 30;
int spouseAge = 31;
request.addParameter("name", name);
request.addParameter("age", "" + age);
request.addParameter("spouse", spouseName);
request.addParameter("spouse.age", "" + spouseAge);
ModelAndView mav = tc.handleRenderRequest(request, response);
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertEquals(name, command.getName());
assertEquals(age, command.getAge());
assertNotNull(command.getSpouse());
assertEquals(spouseName, command.getSpouse().getName());
assertEquals(spouseAge, command.getSpouse().getAge());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be no errors", 0, errors.getErrorCount());
}
public void testWithValidatorNotSupportingCommandClass() throws Exception {
Validator v = new Validator() {
public boolean supports(Class c) {
return false;
}
public void validate(Object o, Errors e) {}
};
TestController tc = new TestController();
tc.setValidator(v);
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
try {
tc.handleRenderRequest(request, response);
fail("Should have thrown IllegalArgumentException");
}
catch(IllegalArgumentException e) {
// expected
}
}
public void testWithValidatorAddingGlobalError() throws Exception {
final String errorCode = "someCode";
final String defaultMessage = "validation error!";
TestController tc = new TestController();
tc.setValidator(new Validator() {
public boolean supports(Class c) {
return TestBean.class.isAssignableFrom(c);
}
public void validate(Object o, Errors e) {
e.reject(errorCode, defaultMessage);
}
});
MockRenderRequest request = new MockRenderRequest();
MockRenderResponse response = new MockRenderResponse();
ModelAndView mav = tc.handleRenderRequest(request, response);
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be 1 error", 1, errors.getErrorCount());
ObjectError error = errors.getGlobalError();
assertEquals(error.getCode(), errorCode);
assertEquals(error.getDefaultMessage(), defaultMessage);
}
public void testWithValidatorAndNullFieldError() throws Exception {
final String errorCode = "someCode";
final String defaultMessage = "validation error!";
TestController tc = new TestController();
tc.setValidator(new Validator() {
public boolean supports(Class c) {
return TestBean.class.isAssignableFrom(c);
}
public void validate(Object o, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", errorCode, defaultMessage);
}
});
MockRenderRequest request = new MockRenderRequest();
int age = 32;
request.setParameter("age", "" + age);
MockRenderResponse response = new MockRenderResponse();
ModelAndView mav = tc.handleRenderRequest(request, response);
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertNull("name should be null", command.getName());
assertEquals(age, command.getAge());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be 1 error", 1, errors.getErrorCount());
FieldError error = errors.getFieldError("name");
assertEquals(error.getCode(), errorCode);
assertEquals(error.getDefaultMessage(), defaultMessage);
}
public void testWithValidatorAndWhitespaceFieldError() throws Exception {
final String errorCode = "someCode";
final String defaultMessage = "validation error!";
TestController tc = new TestController();
tc.setValidator(new Validator() {
public boolean supports(Class c) {
return TestBean.class.isAssignableFrom(c);
}
public void validate(Object o, Errors e) {
ValidationUtils.rejectIfEmptyOrWhitespace(e, "name", errorCode, defaultMessage);
}
});
MockRenderRequest request = new MockRenderRequest();
int age = 32;
String whitespace = " \t ";
request.setParameter("age", "" + age);
request.setParameter("name", whitespace);
MockRenderResponse response = new MockRenderResponse();
ModelAndView mav = tc.handleRenderRequest(request, response);
TestBean command = (TestBean)mav.getModel().get(tc.getCommandName());
assertTrue(command.getName().equals(whitespace));
assertEquals(age, command.getAge());
BindException errors = (BindException)mav.getModel().get(ERRORS_KEY);
assertEquals("There should be 1 error", 1, errors.getErrorCount());
FieldError error = errors.getFieldError("name");
assertEquals("rejected value should contain whitespace", whitespace, error.getRejectedValue());
assertEquals(error.getCode(), errorCode);
assertEquals(error.getDefaultMessage(), defaultMessage);
}
private static class TestController extends AbstractCommandController {
private TestController() {
super(TestBean.class, "testBean");
}
protected void handleAction(ActionRequest request, ActionResponse response, Object command, BindException errors) {
((TestBean)command).setJedi(true);
}
protected ModelAndView handleRender(RenderRequest request, RenderResponse response, Object command, BindException errors) {
assertNotNull(command);
assertNotNull(errors);
Map model = new HashMap();
model.put(getCommandName(), command);
model.put(ERRORS_KEY, errors);
return new ModelAndView(request.getContextPath() + "-view", model);
}
}
}