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