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 static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.common.testing.EqualsTester; 23 import java.lang.reflect.InvocationTargetException; 24 import java.lang.reflect.Method; 25 import junit.framework.TestCase; 26 import org.checkerframework.checker.nullness.qual.Nullable; 27 28 /** 29 * Tests for {@link Subscriber}. 30 * 31 * @author Cliff Biffle 32 * @author Colin Decker 33 */ 34 public class SubscriberTest extends TestCase { 35 36 private static final Object FIXTURE_ARGUMENT = new Object(); 37 38 private EventBus bus; 39 private boolean methodCalled; 40 private @Nullable Object methodArgument; 41 42 @Override setUp()43 protected void setUp() throws Exception { 44 bus = new EventBus(); 45 methodCalled = false; 46 methodArgument = null; 47 } 48 testCreate()49 public void testCreate() { 50 Subscriber s1 = Subscriber.create(bus, this, getTestSubscriberMethod("recordingMethod")); 51 assertThat(s1).isInstanceOf(Subscriber.SynchronizedSubscriber.class); 52 53 // a thread-safe method should not create a synchronized subscriber 54 Subscriber s2 = Subscriber.create(bus, this, getTestSubscriberMethod("threadSafeMethod")); 55 assertThat(s2).isNotInstanceOf(Subscriber.SynchronizedSubscriber.class); 56 } 57 testInvokeSubscriberMethod_basicMethodCall()58 public void testInvokeSubscriberMethod_basicMethodCall() throws Throwable { 59 Method method = getTestSubscriberMethod("recordingMethod"); 60 Subscriber subscriber = Subscriber.create(bus, this, method); 61 62 subscriber.invokeSubscriberMethod(FIXTURE_ARGUMENT); 63 64 assertTrue("Subscriber must call provided method", methodCalled); 65 assertTrue( 66 "Subscriber argument must be exactly the provided object.", 67 methodArgument == FIXTURE_ARGUMENT); 68 } 69 testInvokeSubscriberMethod_exceptionWrapping()70 public void testInvokeSubscriberMethod_exceptionWrapping() throws Throwable { 71 Method method = getTestSubscriberMethod("exceptionThrowingMethod"); 72 Subscriber subscriber = Subscriber.create(bus, this, method); 73 74 InvocationTargetException expected = 75 assertThrows( 76 InvocationTargetException.class, 77 () -> subscriber.invokeSubscriberMethod(FIXTURE_ARGUMENT)); 78 assertThat(expected).hasCauseThat().isInstanceOf(IntentionalException.class); 79 } 80 testInvokeSubscriberMethod_errorPassthrough()81 public void testInvokeSubscriberMethod_errorPassthrough() throws Throwable { 82 Method method = getTestSubscriberMethod("errorThrowingMethod"); 83 Subscriber subscriber = Subscriber.create(bus, this, method); 84 85 assertThrows(JudgmentError.class, () -> subscriber.invokeSubscriberMethod(FIXTURE_ARGUMENT)); 86 } 87 testEquals()88 public void testEquals() throws Exception { 89 Method charAt = String.class.getMethod("charAt", int.class); 90 Method concat = String.class.getMethod("concat", String.class); 91 new EqualsTester() 92 .addEqualityGroup( 93 Subscriber.create(bus, "foo", charAt), Subscriber.create(bus, "foo", charAt)) 94 .addEqualityGroup(Subscriber.create(bus, "bar", charAt)) 95 .addEqualityGroup(Subscriber.create(bus, "foo", concat)) 96 .testEquals(); 97 } 98 getTestSubscriberMethod(String name)99 private Method getTestSubscriberMethod(String name) { 100 try { 101 return getClass().getDeclaredMethod(name, Object.class); 102 } catch (NoSuchMethodException e) { 103 throw new AssertionError(); 104 } 105 } 106 107 /** 108 * Records the provided object in {@link #methodArgument} and sets {@link #methodCalled}. This 109 * method is called reflectively by Subscriber during tests, and must remain public. 110 * 111 * @param arg argument to record. 112 */ 113 @Subscribe recordingMethod(Object arg)114 public void recordingMethod(Object arg) { 115 assertFalse(methodCalled); 116 methodCalled = true; 117 methodArgument = arg; 118 } 119 120 @Subscribe exceptionThrowingMethod(Object arg)121 public void exceptionThrowingMethod(Object arg) throws Exception { 122 throw new IntentionalException(); 123 } 124 125 /** Local exception subclass to check variety of exception thrown. */ 126 class IntentionalException extends Exception { 127 128 private static final long serialVersionUID = -2500191180248181379L; 129 } 130 131 @Subscribe errorThrowingMethod(Object arg)132 public void errorThrowingMethod(Object arg) { 133 throw new JudgmentError(); 134 } 135 136 @Subscribe 137 @AllowConcurrentEvents threadSafeMethod(Object arg)138 public void threadSafeMethod(Object arg) {} 139 140 /** Local Error subclass to check variety of error thrown. */ 141 class JudgmentError extends Error { 142 143 private static final long serialVersionUID = 634248373797713373L; 144 } 145 } 146