1 /* 2 * Copyright 2002-2010 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.web.servlet.view.velocity; 18 19 import static org.easymock.EasyMock.createMock; 20 import static org.easymock.EasyMock.expectLastCall; 21 import static org.easymock.EasyMock.replay; 22 import static org.easymock.EasyMock.verify; 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assert.fail; 27 28 import java.io.IOException; 29 import java.util.HashMap; 30 import java.util.Locale; 31 import java.util.Map; 32 33 import javax.servlet.http.HttpServletRequest; 34 import javax.servlet.http.HttpServletResponse; 35 36 import org.apache.velocity.Template; 37 import org.apache.velocity.app.VelocityEngine; 38 import org.apache.velocity.context.Context; 39 import org.apache.velocity.exception.MethodInvocationException; 40 import org.apache.velocity.exception.ParseErrorException; 41 import org.apache.velocity.tools.generic.DateTool; 42 import org.apache.velocity.tools.generic.MathTool; 43 import org.apache.velocity.tools.generic.NumberTool; 44 import org.junit.Test; 45 import org.springframework.context.ApplicationContextException; 46 import org.springframework.mock.web.MockHttpServletRequest; 47 import org.springframework.mock.web.MockHttpServletResponse; 48 import org.springframework.mock.web.MockServletContext; 49 import org.springframework.web.context.WebApplicationContext; 50 import org.springframework.web.servlet.DispatcherServlet; 51 import org.springframework.web.servlet.View; 52 import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; 53 import org.springframework.web.servlet.support.RequestDataValueProcessor; 54 import org.springframework.web.servlet.view.AbstractView; 55 56 /** 57 * @author Rod Johnson 58 * @author Juergen Hoeller 59 * @author Dave Syer 60 */ 61 public class VelocityViewTests { 62 63 @Test testNoVelocityConfig()64 public void testNoVelocityConfig() throws Exception { 65 VelocityView vv = new VelocityView(); 66 WebApplicationContext wac = createMock(WebApplicationContext.class); 67 wac.getBeansOfType(VelocityConfig.class, true, false); 68 expectLastCall().andReturn(new HashMap<String, Object>()); 69 wac.getParentBeanFactory(); 70 expectLastCall().andReturn(null); 71 replay(wac); 72 73 vv.setUrl("anythingButNull"); 74 try { 75 vv.setApplicationContext(wac); 76 fail(); 77 } 78 catch (ApplicationContextException ex) { 79 // Check there's a helpful error message 80 assertTrue(ex.getMessage().contains("VelocityConfig")); 81 } 82 83 verify(wac); 84 } 85 86 @Test testNoTemplateName()87 public void testNoTemplateName() throws Exception { 88 VelocityView vv = new VelocityView(); 89 try { 90 vv.afterPropertiesSet(); 91 fail("Should have thrown IllegalArgumentException"); 92 } 93 catch (IllegalArgumentException ex) { 94 // Check there's a helpful error message 95 assertTrue(ex.getMessage().indexOf("url") != -1); 96 } 97 } 98 99 @Test testMergeTemplateSucceeds()100 public void testMergeTemplateSucceeds() throws Exception { 101 testValidTemplateName(null); 102 } 103 104 @Test testMergeTemplateFailureWithIOException()105 public void testMergeTemplateFailureWithIOException() throws Exception { 106 testValidTemplateName(new IOException()); 107 } 108 109 @Test testMergeTemplateFailureWithParseErrorException()110 public void testMergeTemplateFailureWithParseErrorException() throws Exception { 111 testValidTemplateName(new ParseErrorException("")); 112 } 113 114 @Test testMergeTemplateFailureWithUnspecifiedException()115 public void testMergeTemplateFailureWithUnspecifiedException() throws Exception { 116 testValidTemplateName(new Exception("")); 117 } 118 119 @Test testMergeTemplateFailureWithMethodInvocationException()120 public void testMergeTemplateFailureWithMethodInvocationException() throws Exception { 121 testValidTemplateName(new MethodInvocationException("Bad template", null, "none", "foo.vm", 1, 100)); 122 } 123 124 /** 125 * @param mergeTemplateFailureException may be null in which case mergeTemplate override will succeed. 126 * If it's non null it will be checked 127 */ testValidTemplateName(final Exception mergeTemplateFailureException)128 private void testValidTemplateName(final Exception mergeTemplateFailureException) throws Exception { 129 Map<String, Object> model = new HashMap<String, Object>(); 130 model.put("foo", "bar"); 131 132 final String templateName = "test.vm"; 133 134 WebApplicationContext wac = createMock(WebApplicationContext.class); 135 MockServletContext sc = new MockServletContext(); 136 sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); 137 138 final Template expectedTemplate = new Template(); 139 VelocityConfig vc = new VelocityConfig() { 140 public VelocityEngine getVelocityEngine() { 141 return new TestVelocityEngine(templateName, expectedTemplate); 142 } 143 }; 144 wac.getBeansOfType(VelocityConfig.class, true, false); 145 Map<String, Object> configurers = new HashMap<String, Object>(); 146 configurers.put("velocityConfigurer", vc); 147 expectLastCall().andReturn(configurers); 148 wac.getParentBeanFactory(); 149 expectLastCall().andReturn(null); 150 wac.getServletContext(); 151 expectLastCall().andReturn(sc).times(3); 152 wac.getBean("requestDataValueProcessor", RequestDataValueProcessor.class); 153 expectLastCall().andReturn(null); 154 replay(wac); 155 156 HttpServletRequest request = new MockHttpServletRequest(); 157 final HttpServletResponse expectedResponse = new MockHttpServletResponse(); 158 159 VelocityView vv = new VelocityView() { 160 protected void mergeTemplate(Template template, Context context, HttpServletResponse response) throws Exception { 161 assertTrue(template == expectedTemplate); 162 assertTrue(context.getKeys().length >= 1); 163 assertTrue(context.get("foo").equals("bar")); 164 assertTrue(response == expectedResponse); 165 if (mergeTemplateFailureException != null) { 166 throw mergeTemplateFailureException; 167 } 168 } 169 }; 170 vv.setUrl(templateName); 171 vv.setApplicationContext(wac); 172 173 try { 174 vv.render(model, request, expectedResponse); 175 if (mergeTemplateFailureException != null) { 176 fail(); 177 } 178 } 179 catch (Exception ex) { 180 assertNotNull(mergeTemplateFailureException); 181 assertEquals(ex, mergeTemplateFailureException); 182 } 183 184 verify(wac); 185 } 186 187 @Test testKeepExistingContentType()188 public void testKeepExistingContentType() throws Exception { 189 final String templateName = "test.vm"; 190 191 WebApplicationContext wac = createMock(WebApplicationContext.class); 192 MockServletContext sc = new MockServletContext(); 193 sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); 194 195 final Template expectedTemplate = new Template(); 196 VelocityConfig vc = new VelocityConfig() { 197 public VelocityEngine getVelocityEngine() { 198 return new TestVelocityEngine(templateName, expectedTemplate); 199 } 200 }; 201 wac.getBeansOfType(VelocityConfig.class, true, false); 202 Map<String, Object> configurers = new HashMap<String, Object>(); 203 configurers.put("velocityConfigurer", vc); 204 expectLastCall().andReturn(configurers); 205 wac.getParentBeanFactory(); 206 expectLastCall().andReturn(null); 207 wac.getServletContext(); 208 expectLastCall().andReturn(sc).times(3); 209 wac.getBean("requestDataValueProcessor", RequestDataValueProcessor.class); 210 expectLastCall().andReturn(null); 211 replay(wac); 212 213 HttpServletRequest request = new MockHttpServletRequest(); 214 final HttpServletResponse expectedResponse = new MockHttpServletResponse(); 215 expectedResponse.setContentType("myContentType"); 216 217 VelocityView vv = new VelocityView() { 218 protected void mergeTemplate(Template template, Context context, HttpServletResponse response) { 219 assertTrue(template == expectedTemplate); 220 assertTrue(response == expectedResponse); 221 } 222 protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception { 223 model.put("myHelper", "myValue"); 224 } 225 }; 226 227 vv.setUrl(templateName); 228 vv.setApplicationContext(wac); 229 vv.render(new HashMap<String, Object>(), request, expectedResponse); 230 231 verify(wac); 232 assertEquals("myContentType", expectedResponse.getContentType()); 233 } 234 235 @Test testExposeHelpers()236 public void testExposeHelpers() throws Exception { 237 final String templateName = "test.vm"; 238 239 WebApplicationContext wac = createMock(WebApplicationContext.class); 240 wac.getParentBeanFactory(); 241 expectLastCall().andReturn(null); 242 wac.getServletContext(); 243 expectLastCall().andReturn(new MockServletContext()); 244 245 final Template expectedTemplate = new Template(); 246 VelocityConfig vc = new VelocityConfig() { 247 public VelocityEngine getVelocityEngine() { 248 return new TestVelocityEngine(templateName, expectedTemplate); 249 } 250 }; 251 wac.getBeansOfType(VelocityConfig.class, true, false); 252 Map<String, Object> configurers = new HashMap<String, Object>(); 253 configurers.put("velocityConfigurer", vc); 254 expectLastCall().andReturn(configurers); 255 replay(wac); 256 257 258 // let it ask for locale 259 HttpServletRequest req = createMock(HttpServletRequest.class); 260 req.getAttribute(View.PATH_VARIABLES); 261 expectLastCall().andReturn(null); 262 req.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE); 263 expectLastCall().andReturn(new AcceptHeaderLocaleResolver()); 264 req.getLocale(); 265 expectLastCall().andReturn(Locale.CANADA); 266 replay(req); 267 268 final HttpServletResponse expectedResponse = new MockHttpServletResponse(); 269 270 VelocityView vv = new VelocityView() { 271 protected void mergeTemplate(Template template, Context context, HttpServletResponse response) throws Exception { 272 assertTrue(template == expectedTemplate); 273 assertTrue(response == expectedResponse); 274 275 assertEquals("myValue", context.get("myHelper")); 276 assertTrue(context.get("math") instanceof MathTool); 277 278 assertTrue(context.get("dateTool") instanceof DateTool); 279 DateTool dateTool = (DateTool) context.get("dateTool"); 280 assertTrue(dateTool.getLocale().equals(Locale.CANADA)); 281 282 assertTrue(context.get("numberTool") instanceof NumberTool); 283 NumberTool numberTool = (NumberTool) context.get("numberTool"); 284 assertTrue(numberTool.getLocale().equals(Locale.CANADA)); 285 } 286 287 protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception { 288 model.put("myHelper", "myValue"); 289 } 290 }; 291 292 vv.setUrl(templateName); 293 vv.setApplicationContext(wac); 294 Map<String, Class> toolAttributes = new HashMap<String, Class>(); 295 toolAttributes.put("math", MathTool.class); 296 vv.setToolAttributes(toolAttributes); 297 vv.setDateToolAttribute("dateTool"); 298 vv.setNumberToolAttribute("numberTool"); 299 vv.setExposeSpringMacroHelpers(false); 300 301 vv.render(new HashMap<String, Object>(), req, expectedResponse); 302 303 verify(wac); 304 verify(req); 305 assertEquals(AbstractView.DEFAULT_CONTENT_TYPE, expectedResponse.getContentType()); 306 } 307 308 } 309