001 // Copyright 2005, 2006 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.listener; 016 017 import org.apache.hivemind.ApplicationRuntimeException; 018 import org.apache.tapestry.BaseComponentTestCase; 019 import org.apache.tapestry.IPage; 020 import org.apache.tapestry.IRequestCycle; 021 import org.apache.tapestry.engine.ILink; 022 import org.apache.tapestry.event.BrowserEvent; 023 import static org.easymock.EasyMock.expect; 024 import org.testng.annotations.Test; 025 026 import java.lang.reflect.Method; 027 028 /** 029 * Tests for {@link org.apache.tapestry.listener.ListenerMapSourceImpl} and 030 * {@link org.apache.tapestry.listener.ListenerMethodInvokerImpl}. 031 * 032 * @author Howard M. Lewis Ship 033 * @since 4.0 034 */ 035 @Test 036 public class TestListenerMapSource extends BaseComponentTestCase 037 { 038 039 private IRequestCycle newLCycle(Object[] listenerParameters) 040 { 041 IRequestCycle cycle = newCycle(); 042 043 expect(cycle.getListenerParameters()).andReturn(listenerParameters); 044 045 return cycle; 046 } 047 048 private Method findMethod(Class clazz, String name) 049 { 050 Method[] methods = clazz.getMethods(); 051 052 for(int i = 0; i < methods.length; i++) 053 { 054 if (methods[i].getName().equals(name)) return methods[i]; 055 } 056 057 throw new IllegalArgumentException("No method '" + name + "' in " + clazz + "."); 058 } 059 060 private void attemptReturnType(boolean expected, Class clazz, String methodName) 061 { 062 Method m = findMethod(clazz, methodName); 063 064 ListenerMapSourceImpl lms = new ListenerMapSourceImpl(); 065 066 assertEquals(expected, lms.isAcceptibleListenerMethodReturnType(m)); 067 } 068 069 public void testAcceptibleListenerMethodReturnTypes() 070 { 071 Class clazz = ListenerMethodHolder.class; 072 073 attemptReturnType(true, clazz, "fred"); 074 attemptReturnType(true, clazz, "returnsString"); 075 attemptReturnType(true, clazz, "returnsBasePage"); 076 attemptReturnType(false, clazz, "returnsObject"); 077 attemptReturnType(false, clazz, "returnsInt"); 078 attemptReturnType(true, clazz, "returnsLink"); 079 } 080 081 public void testFoundWithParameters() 082 { 083 IRequestCycle cycle = newLCycle(new Object[] { "Hello", new Integer(7) }); 084 ListenerMethodHolder holder = newHolder(); 085 086 holder.fred("Hello", 7); 087 088 replay(); 089 090 ListenerMapSource source = new ListenerMapSourceImpl(); 091 092 ListenerMap map = source.getListenerMapForObject(holder); 093 094 map.getListener("fred").actionTriggered(null, cycle); 095 096 verify(); 097 } 098 099 public void testFoundWithCycleAndParameters() 100 { 101 IRequestCycle cycle = newLCycle(new Object[] { new Integer(7) }); 102 ListenerMethodHolder holder = newHolder(); 103 104 holder.wilma(cycle, 7); 105 106 replay(); 107 108 ListenerMapSource source = new ListenerMapSourceImpl(); 109 110 ListenerMap map = source.getListenerMapForObject(holder); 111 112 map.getListener("wilma").actionTriggered(null, cycle); 113 114 verify(); 115 } 116 117 public void testFoundWithAllParameters() 118 { 119 BrowserEvent event = new BrowserEvent("onClick", null); 120 IRequestCycle cycle = newLCycle(new Object[] { new Integer(8), event }); 121 ListenerMethodHolder holder = newHolder(); 122 123 holder.bangbangClicked(cycle, event, 8); 124 125 replay(); 126 127 ListenerMapSource source = new ListenerMapSourceImpl(); 128 129 ListenerMap map = source.getListenerMapForObject(holder); 130 131 map.getListener("bangbangClicked").actionTriggered(null, cycle); 132 133 verify(); 134 } 135 136 /** 137 * No exact match on parameter count, fall through to the no-arguments 138 * method implementation. 139 */ 140 141 public void testNoParameterMatch() 142 { 143 IRequestCycle cycle = newLCycle(new Object[] { "Hello", new Integer(7) }); 144 ListenerMethodHolder holder = newHolder(); 145 146 holder.barney(); 147 148 replay(); 149 150 ListenerMapSource source = new ListenerMapSourceImpl(); 151 152 ListenerMap map = source.getListenerMapForObject(holder); 153 154 map.getListener("barney").actionTriggered(null, cycle); 155 156 verify(); 157 } 158 159 public void testFallbackToJustCycle() 160 { 161 IRequestCycle cycle = newLCycle(new Object[] { "Hello", new Integer(7) }); 162 163 ListenerMethodHolder holder = newHolder(); 164 165 holder.pebbles(cycle); 166 167 replay(); 168 169 ListenerMapSource source = new ListenerMapSourceImpl(); 170 171 ListenerMap map = source.getListenerMapForObject(holder); 172 173 map.getListener("pebbles").actionTriggered(null, cycle); 174 175 verify(); 176 } 177 178 public void testReturnPageName() 179 { 180 IRequestCycle cycle = newLCycle(null); 181 ListenerMethodHolder holder = new ListenerMethodHolder("PageName"); 182 183 cycle.activate("PageName"); 184 185 replay(); 186 187 ListenerMapSource source = new ListenerMapSourceImpl(); 188 189 ListenerMap map = source.getListenerMapForObject(holder); 190 191 map.getListener("returnsPageName").actionTriggered(null, cycle); 192 193 verify(); 194 } 195 196 public void testReturnLink() 197 { 198 IRequestCycle cycle = newLCycle(null); 199 200 ILink link = newLink("http://foo/bar"); 201 202 cycle.sendRedirect("http://foo/bar"); 203 204 ListenerMethodHolder holder = new ListenerMethodHolder(link); 205 206 replay(); 207 208 ListenerMapSource source = new ListenerMapSourceImpl(); 209 210 ListenerMap map = source.getListenerMapForObject(holder); 211 212 map.getListener("returnsLink").actionTriggered(null, cycle); 213 214 verify(); 215 } 216 217 private ILink newLink(String absoluteURL) 218 { 219 ILink link = newMock(ILink.class); 220 221 expect(link.getAbsoluteURL()).andReturn(absoluteURL); 222 223 return link; 224 } 225 226 public void testReturnPageInstance() 227 { 228 IPage page = newMock(IPage.class); 229 IRequestCycle cycle = newLCycle(null); 230 ListenerMethodHolder holder = new ListenerMethodHolder(page); 231 232 cycle.activate(page); 233 234 replay(); 235 236 ListenerMapSource source = new ListenerMapSourceImpl(); 237 238 ListenerMap map = source.getListenerMapForObject(holder); 239 240 map.getListener("returnsPage").actionTriggered(null, cycle); 241 242 verify(); 243 } 244 245 @Test(expectedExceptions = ApplicationRuntimeException.class) 246 public void test_No_Match() 247 { 248 IRequestCycle cycle = newLCycle(new Object[] { "Hello", new Integer(7) }); 249 250 replay(); 251 252 ListenerMethodHolder holder = new ListenerMethodHolder(); 253 254 ListenerMapSource source = new ListenerMapSourceImpl(); 255 256 ListenerMap map = source.getListenerMapForObject(holder); 257 258 map.getListener("noMatchFound").actionTriggered(null, cycle); 259 260 verify(); 261 } 262 263 public void testMismatchedTypes() 264 { 265 IRequestCycle cycle = newLCycle(new Object[] { "Hello" }); 266 267 replay(); 268 269 ListenerMethodHolder holder = new ListenerMethodHolder(); 270 271 ListenerMapSource source = new ListenerMapSourceImpl(); 272 273 ListenerMap map = source.getListenerMapForObject(holder); 274 275 try 276 { 277 map.getListener("wrongTypes").actionTriggered(null, cycle); 278 unreachable(); 279 } 280 catch (ApplicationRuntimeException ex) 281 { 282 assertEquals(IllegalArgumentException.class, ex.getRootCause().getClass()); 283 assertTrue(ex.getMessage().startsWith( 284 "Failure invoking listener method 'public void " 285 + "org.apache.tapestry.listener.ListenerMethodHolder." 286 + "wrongTypes(java.util.Map)' on ListenerMethodHolder:")); 287 288 // TODO: IBM jre doesn't format these messages the same as sun's 289 // jre, 290 // IBM's message has no message string source for the 291 // IllegalArgumentException 292 assertSame(holder, ex.getComponent()); 293 } 294 295 verify(); 296 } 297 298 public void testInvocationTargetException() 299 { 300 IRequestCycle cycle = newLCycle(new Object[] { "Hello", new Integer(7) }); 301 302 ListenerMethodHolder holder = new ListenerMethodHolder(); 303 304 RuntimeException exception = new IllegalArgumentException("Just for kicks."); 305 306 holder.setException(exception); 307 308 replay(); 309 310 ListenerMapSource source = new ListenerMapSourceImpl(); 311 312 ListenerMap map = source.getListenerMapForObject(holder); 313 314 try 315 { 316 map.getListener("throwsException").actionTriggered(null, cycle); 317 unreachable(); 318 } 319 catch (ApplicationRuntimeException ex) 320 { 321 assertEquals( 322 "Failure invoking listener method 'public void org.apache.tapestry.listener.ListenerMethodHolder.throwsException()' on ListenerMethodHolder: Just for kicks.", 323 ex.getMessage()); 324 assertSame(holder, ex.getComponent()); 325 assertSame(exception, ex.getRootCause()); 326 } 327 328 verify(); 329 } 330 331 public void testInvocationTargetExceptionForApplicationRuntimeException() 332 { 333 IRequestCycle cycle = newLCycle(new Object[] { "Hello", new Integer(7) }); 334 335 ListenerMethodHolder holder = new ListenerMethodHolder(); 336 337 RuntimeException exception = new ApplicationRuntimeException("Just for kicks."); 338 339 holder.setException(exception); 340 341 replay(); 342 343 ListenerMapSource source = new ListenerMapSourceImpl(); 344 345 ListenerMap map = source.getListenerMapForObject(holder); 346 347 try 348 { 349 map.getListener("throwsException").actionTriggered(null, cycle); 350 unreachable(); 351 } 352 catch (ApplicationRuntimeException ex) 353 { 354 assertSame(exception, ex); 355 } 356 357 verify(); 358 } 359 360 private ListenerMethodHolder newHolder() 361 { 362 return (ListenerMethodHolder)newInstance(ListenerMethodHolder.class); 363 } 364 }