1 /* 2 * Copyright (C) 2007 The Guava 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 com.google.common.eventbus; 18 19 import java.lang.reflect.InvocationTargetException; 20 import java.lang.reflect.Method; 21 import junit.framework.TestCase; 22 23 /** 24 * Test case for {@link EventHandler}. 25 * 26 * @author Cliff Biffle 27 */ 28 public class EventHandlerTest extends TestCase { 29 30 private static final Object FIXTURE_ARGUMENT = new Object(); 31 32 private boolean methodCalled; 33 private Object methodArgument; 34 35 @Override protected void setUp() throws Exception { 36 super.setUp(); 37 38 methodCalled = false; 39 methodArgument = null; 40 } 41 42 /** 43 * Checks that a no-frills, no-issues method call is properly executed. 44 * 45 * @throws Exception if the aforementioned proper execution is not to be had. 46 */ 47 public void testBasicMethodCall() throws Exception { 48 Method method = getRecordingMethod(); 49 50 EventHandler handler = new EventHandler(this, method); 51 52 handler.handleEvent(FIXTURE_ARGUMENT); 53 54 assertTrue("Handler must call provided method.", methodCalled); 55 assertTrue("Handler argument must be *exactly* the provided object.", 56 methodArgument == FIXTURE_ARGUMENT); 57 } 58 59 /** 60 * Checks that EventHandler's constructor disallows null methods. 61 */ 62 public void testRejectionOfNullMethods() { 63 try { 64 new EventHandler(this, null); 65 fail("EventHandler must immediately reject null methods."); 66 } catch (NullPointerException e) { 67 // Hooray! 68 } 69 } 70 71 /** 72 * Checks that EventHandler's constructor disallows null targets. 73 */ 74 public void testRejectionOfNullTargets() { 75 Method method = getRecordingMethod(); 76 try { 77 new EventHandler(null, method); 78 fail("EventHandler must immediately reject null targets."); 79 } catch (NullPointerException e) { 80 // Huzzah! 81 } 82 } 83 84 public void testExceptionWrapping() { 85 Method method = getExceptionThrowingMethod(); 86 EventHandler handler = new EventHandler(this, method); 87 88 try { 89 handler.handleEvent(new Object()); 90 fail("Handlers whose methods throw must throw InvocationTargetException"); 91 } catch (InvocationTargetException e) { 92 assertTrue("Expected exception must be wrapped.", 93 e.getCause() instanceof IntentionalException); 94 } 95 } 96 97 public void testErrorPassthrough() throws InvocationTargetException { 98 Method method = getErrorThrowingMethod(); 99 EventHandler handler = new EventHandler(this, method); 100 101 try { 102 handler.handleEvent(new Object()); 103 fail("Handlers whose methods throw Errors must rethrow them"); 104 } catch (JudgmentError e) { 105 // Expected. 106 } 107 } 108 109 /** 110 * Gets a reference to {@link #recordingMethod(Object)}. 111 * 112 * @return a Method wrapping {@link #recordingMethod(Object)}. 113 * @throws IllegalStateException if executed in a context where reflection is 114 * unavailable. 115 * @throws AssertionError if something odd has happened to 116 * {@link #recordingMethod(Object)}. 117 */ 118 private Method getRecordingMethod() { 119 Method method; 120 try { 121 method = getClass().getMethod("recordingMethod", Object.class); 122 } catch (SecurityException e) { 123 throw new IllegalStateException("This test needs access to reflection."); 124 } catch (NoSuchMethodException e) { 125 throw new AssertionError( 126 "Someone changed EventHandlerTest#recordingMethod's visibility, " + 127 "signature, or removed it entirely. (Must be public.)"); 128 } 129 return method; 130 } 131 132 /** 133 * Gets a reference to {@link #exceptionThrowingMethod(Object)}. 134 * 135 * @return a Method wrapping {@link #exceptionThrowingMethod(Object)}. 136 * @throws IllegalStateException if executed in a context where reflection is 137 * unavailable. 138 * @throws AssertionError if something odd has happened to 139 * {@link #exceptionThrowingMethod(Object)}. 140 */ 141 private Method getExceptionThrowingMethod() { 142 Method method; 143 try { 144 method = getClass().getMethod("exceptionThrowingMethod", Object.class); 145 } catch (SecurityException e) { 146 throw new IllegalStateException("This test needs access to reflection."); 147 } catch (NoSuchMethodException e) { 148 throw new AssertionError( 149 "Someone changed EventHandlerTest#exceptionThrowingMethod's " + 150 "visibility, signature, or removed it entirely. (Must be public.)"); 151 } 152 return method; 153 } 154 155 /** 156 * Gets a reference to {@link #errorThrowingMethod(Object)}. 157 * 158 * @return a Method wrapping {@link #errorThrowingMethod(Object)}. 159 * @throws IllegalStateException if executed in a context where reflection is 160 * unavailable. 161 * @throws AssertionError if something odd has happened to 162 * {@link #errorThrowingMethod(Object)}. 163 */ 164 private Method getErrorThrowingMethod() { 165 Method method; 166 try { 167 method = getClass().getMethod("errorThrowingMethod", Object.class); 168 } catch (SecurityException e) { 169 throw new IllegalStateException("This test needs access to reflection."); 170 } catch (NoSuchMethodException e) { 171 throw new AssertionError( 172 "Someone changed EventHandlerTest#errorThrowingMethod's " + 173 "visibility, signature, or removed it entirely. (Must be public.)"); 174 } 175 return method; 176 } 177 178 /** 179 * Records the provided object in {@link #methodArgument} and sets 180 * {@link #methodCalled}. This method is called reflectively by EventHandler 181 * during tests, and must remain public. 182 * 183 * @param arg argument to record. 184 */ 185 public void recordingMethod(Object arg) { 186 if (methodCalled == true) { 187 throw new IllegalStateException("Method called more than once."); 188 } 189 methodCalled = true; 190 methodArgument = arg; 191 } 192 193 public void exceptionThrowingMethod(Object arg) throws Exception { 194 throw new IntentionalException(); 195 } 196 /** Local exception subclass to check variety of exception thrown. */ 197 class IntentionalException extends Exception { 198 private static final long serialVersionUID = -2500191180248181379L; 199 } 200 201 public void errorThrowingMethod(Object arg) { 202 throw new JudgmentError(); 203 } 204 /** Local Error subclass to check variety of error thrown. */ 205 class JudgmentError extends Error { 206 private static final long serialVersionUID = 634248373797713373L; 207 } 208 } 209