/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.eventbus;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import junit.framework.TestCase;
/**
* Test case for {@link EventHandler}.
*
* @author Cliff Biffle
*/
public class EventHandlerTest extends TestCase {
private static final Object FIXTURE_ARGUMENT = new Object();
private boolean methodCalled;
private Object methodArgument;
@Override protected void setUp() throws Exception {
super.setUp();
methodCalled = false;
methodArgument = null;
}
/**
* Checks that a no-frills, no-issues method call is properly executed.
*
* @throws Exception if the aforementioned proper execution is not to be had.
*/
public void testBasicMethodCall() throws Exception {
Method method = getRecordingMethod();
EventHandler handler = new EventHandler(this, method);
handler.handleEvent(FIXTURE_ARGUMENT);
assertTrue("Handler must call provided method.", methodCalled);
assertTrue("Handler argument must be *exactly* the provided object.",
methodArgument == FIXTURE_ARGUMENT);
}
/**
* Checks that EventHandler's constructor disallows null methods.
*/
public void testRejectionOfNullMethods() {
try {
new EventHandler(this, null);
fail("EventHandler must immediately reject null methods.");
} catch (NullPointerException e) {
// Hooray!
}
}
/**
* Checks that EventHandler's constructor disallows null targets.
*/
public void testRejectionOfNullTargets() {
Method method = getRecordingMethod();
try {
new EventHandler(null, method);
fail("EventHandler must immediately reject null targets.");
} catch (NullPointerException e) {
// Huzzah!
}
}
public void testExceptionWrapping() {
Method method = getExceptionThrowingMethod();
EventHandler handler = new EventHandler(this, method);
try {
handler.handleEvent(new Object());
fail("Handlers whose methods throw must throw InvocationTargetException");
} catch (InvocationTargetException e) {
assertTrue("Expected exception must be wrapped.",
e.getCause() instanceof IntentionalException);
}
}
public void testErrorPassthrough() throws InvocationTargetException {
Method method = getErrorThrowingMethod();
EventHandler handler = new EventHandler(this, method);
try {
handler.handleEvent(new Object());
fail("Handlers whose methods throw Errors must rethrow them");
} catch (JudgmentError e) {
// Expected.
}
}
/**
* Gets a reference to {@link #recordingMethod(Object)}.
*
* @return a Method wrapping {@link #recordingMethod(Object)}.
* @throws IllegalStateException if executed in a context where reflection is
* unavailable.
* @throws AssertionError if something odd has happened to
* {@link #recordingMethod(Object)}.
*/
private Method getRecordingMethod() {
Method method;
try {
method = getClass().getMethod("recordingMethod", Object.class);
} catch (SecurityException e) {
throw new IllegalStateException("This test needs access to reflection.");
} catch (NoSuchMethodException e) {
throw new AssertionError(
"Someone changed EventHandlerTest#recordingMethod's visibility, " +
"signature, or removed it entirely. (Must be public.)");
}
return method;
}
/**
* Gets a reference to {@link #exceptionThrowingMethod(Object)}.
*
* @return a Method wrapping {@link #exceptionThrowingMethod(Object)}.
* @throws IllegalStateException if executed in a context where reflection is
* unavailable.
* @throws AssertionError if something odd has happened to
* {@link #exceptionThrowingMethod(Object)}.
*/
private Method getExceptionThrowingMethod() {
Method method;
try {
method = getClass().getMethod("exceptionThrowingMethod", Object.class);
} catch (SecurityException e) {
throw new IllegalStateException("This test needs access to reflection.");
} catch (NoSuchMethodException e) {
throw new AssertionError(
"Someone changed EventHandlerTest#exceptionThrowingMethod's " +
"visibility, signature, or removed it entirely. (Must be public.)");
}
return method;
}
/**
* Gets a reference to {@link #errorThrowingMethod(Object)}.
*
* @return a Method wrapping {@link #errorThrowingMethod(Object)}.
* @throws IllegalStateException if executed in a context where reflection is
* unavailable.
* @throws AssertionError if something odd has happened to
* {@link #errorThrowingMethod(Object)}.
*/
private Method getErrorThrowingMethod() {
Method method;
try {
method = getClass().getMethod("errorThrowingMethod", Object.class);
} catch (SecurityException e) {
throw new IllegalStateException("This test needs access to reflection.");
} catch (NoSuchMethodException e) {
throw new AssertionError(
"Someone changed EventHandlerTest#errorThrowingMethod's " +
"visibility, signature, or removed it entirely. (Must be public.)");
}
return method;
}
/**
* Records the provided object in {@link #methodArgument} and sets
* {@link #methodCalled}. This method is called reflectively by EventHandler
* during tests, and must remain public.
*
* @param arg argument to record.
*/
public void recordingMethod(Object arg) {
if (methodCalled == true) {
throw new IllegalStateException("Method called more than once.");
}
methodCalled = true;
methodArgument = arg;
}
public void exceptionThrowingMethod(Object arg) throws Exception {
throw new IntentionalException();
}
/** Local exception subclass to check variety of exception thrown. */
class IntentionalException extends Exception {
private static final long serialVersionUID = -2500191180248181379L;
}
public void errorThrowingMethod(Object arg) {
throw new JudgmentError();
}
/** Local Error subclass to check variety of error thrown. */
class JudgmentError extends Error {
private static final long serialVersionUID = 634248373797713373L;
}
}