From 2a0687c8905d9f9d1c8d4e1dee255a8ceabba5e5 Mon Sep 17 00:00:00 2001 From: David Srbecky Date: Wed, 24 Feb 2021 15:52:50 +0000 Subject: Revert "Remove support for stuck threads" Revert submission 1601635 Reason for revert: b/181123058 Reverted Changes: I8f5cd1266:Remove support for stuck threads Ifdb59336d:Remove DisableOnDebug (new in 4.12) as it is not s... I6abae5aed:Extra generic type information to aid certain java... I5ec909df6:Upgrade external/junit to 4.13.2 Change-Id: Icf0a7b88b0004e60cd4139cb10be62af5bdc68d2 --- .../internal/runners/statements/FailOnTimeout.java | 155 ++++++++++++++++++++- 1 file changed, 153 insertions(+), 2 deletions(-) (limited to 'src/main/java/org/junit/internal') diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java index 9fad35b..9362cc1 100644 --- a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java +++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java @@ -1,5 +1,8 @@ package org.junit.internal.runners.statements; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -7,6 +10,9 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.internal.management.ManagementFactory; +import org.junit.internal.management.ThreadMXBean; +import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; import org.junit.runners.model.TestTimedOutException; @@ -14,6 +20,7 @@ public class FailOnTimeout extends Statement { private final Statement originalStatement; private final TimeUnit timeUnit; private final long timeout; + private final boolean lookForStuckThread; /** * Returns a new builder for building an instance. @@ -40,6 +47,7 @@ public class FailOnTimeout extends Statement { originalStatement = statement; timeout = builder.timeout; timeUnit = builder.unit; + lookForStuckThread = builder.lookForStuckThread; } /** @@ -48,6 +56,7 @@ public class FailOnTimeout extends Statement { * @since 4.12 */ public static class Builder { + private boolean lookForStuckThread = false; private long timeout = 0; private TimeUnit unit = TimeUnit.SECONDS; @@ -79,6 +88,20 @@ public class FailOnTimeout extends Statement { return this; } + /** + * Specifies whether to look for a stuck thread. If a timeout occurs and this + * feature is enabled, the test will look for a thread that appears to be stuck + * and dump its backtrace. This feature is experimental. Behavior may change + * after the 4.12 release in response to feedback. + * + * @param enable {@code true} to enable the feature + * @return {@code this} for method chaining. + */ + public Builder withLookingForStuckThread(boolean enable) { + this.lookForStuckThread = enable; + return this; + } + /** * Builds a {@link FailOnTimeout} instance using the values in this builder, * wrapping the given statement. @@ -97,7 +120,8 @@ public class FailOnTimeout extends Statement { public void evaluate() throws Throwable { CallableStatement callable = new CallableStatement(); FutureTask task = new FutureTask(callable); - Thread thread = new Thread(task, "Time-limited test"); + ThreadGroup threadGroup = threadGroupForNewThread(); + Thread thread = new Thread(threadGroup, task, "Time-limited test"); thread.setDaemon(true); thread.start(); callable.awaitStarted(); @@ -107,6 +131,31 @@ public class FailOnTimeout extends Statement { } } + private ThreadGroup threadGroupForNewThread() { + if (!lookForStuckThread) { + // Use the default ThreadGroup (usually the one from the current + // thread). + return null; + } + + // Create the thread in a new ThreadGroup, so if the time-limited thread + // becomes stuck, getStuckThread() can find the thread likely to be the + // culprit. + ThreadGroup threadGroup = new ThreadGroup("FailOnTimeoutGroup"); + if (!threadGroup.isDaemon()) { + // Mark the new ThreadGroup as a daemon thread group, so it will be + // destroyed after the time-limited thread completes. By ensuring the + // ThreadGroup is destroyed, any data associated with the ThreadGroup + // (ex: via java.beans.ThreadGroupContext) is destroyed. + try { + threadGroup.setDaemon(true); + } catch (SecurityException e) { + // Swallow the exception to keep the same behavior as in JUnit 4.12. + } + } + return threadGroup; + } + /** * Wait for the test task, returning the exception thrown by the test if the * test failed, an exception indicating a timeout if the test timed out, or @@ -131,12 +180,114 @@ public class FailOnTimeout extends Statement { private Exception createTimeoutException(Thread thread) { StackTraceElement[] stackTrace = thread.getStackTrace(); + final Thread stuckThread = lookForStuckThread ? getStuckThread(thread) : null; Exception currThreadException = new TestTimedOutException(timeout, timeUnit); if (stackTrace != null) { currThreadException.setStackTrace(stackTrace); thread.interrupt(); } - return currThreadException; + if (stuckThread != null) { + Exception stuckThreadException = + new Exception("Appears to be stuck in thread " + + stuckThread.getName()); + stuckThreadException.setStackTrace(getStackTrace(stuckThread)); + return new MultipleFailureException( + Arrays.asList(currThreadException, stuckThreadException)); + } else { + return currThreadException; + } + } + + /** + * Retrieves the stack trace for a given thread. + * @param thread The thread whose stack is to be retrieved. + * @return The stack trace; returns a zero-length array if the thread has + * terminated or the stack cannot be retrieved for some other reason. + */ + private StackTraceElement[] getStackTrace(Thread thread) { + try { + return thread.getStackTrace(); + } catch (SecurityException e) { + return new StackTraceElement[0]; + } + } + + /** + * Determines whether the test appears to be stuck in some thread other than + * the "main thread" (the one created to run the test). This feature is experimental. + * Behavior may change after the 4.12 release in response to feedback. + * @param mainThread The main thread created by {@code evaluate()} + * @return The thread which appears to be causing the problem, if different from + * {@code mainThread}, or {@code null} if the main thread appears to be the + * problem or if the thread cannot be determined. The return value is never equal + * to {@code mainThread}. + */ + private Thread getStuckThread(Thread mainThread) { + List threadsInGroup = getThreadsInGroup(mainThread.getThreadGroup()); + if (threadsInGroup.isEmpty()) { + return null; + } + + // Now that we have all the threads in the test's thread group: Assume that + // any thread we're "stuck" in is RUNNABLE. Look for all RUNNABLE threads. + // If just one, we return that (unless it equals threadMain). If there's more + // than one, pick the one that's using the most CPU time, if this feature is + // supported. + Thread stuckThread = null; + long maxCpuTime = 0; + for (Thread thread : threadsInGroup) { + if (thread.getState() == Thread.State.RUNNABLE) { + long threadCpuTime = cpuTime(thread); + if (stuckThread == null || threadCpuTime > maxCpuTime) { + stuckThread = thread; + maxCpuTime = threadCpuTime; + } + } + } + return (stuckThread == mainThread) ? null : stuckThread; + } + + /** + * Returns all active threads belonging to a thread group. + * @param group The thread group. + * @return The active threads in the thread group. The result should be a + * complete list of the active threads at some point in time. Returns an empty list + * if this cannot be determined, e.g. because new threads are being created at an + * extremely fast rate. + */ + private List getThreadsInGroup(ThreadGroup group) { + final int activeThreadCount = group.activeCount(); // this is just an estimate + int threadArraySize = Math.max(activeThreadCount * 2, 100); + for (int loopCount = 0; loopCount < 5; loopCount++) { + Thread[] threads = new Thread[threadArraySize]; + int enumCount = group.enumerate(threads); + if (enumCount < threadArraySize) { + return Arrays.asList(threads).subList(0, enumCount); + } + // if there are too many threads to fit into the array, enumerate's result + // is >= the array's length; therefore we can't trust that it returned all + // the threads. Try again. + threadArraySize += 100; + } + // threads are proliferating too fast for us. Bail before we get into + // trouble. + return Collections.emptyList(); + } + + /** + * Returns the CPU time used by a thread, if possible. + * @param thr The thread to query. + * @return The CPU time used by {@code thr}, or 0 if it cannot be determined. + */ + private long cpuTime(Thread thr) { + ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); + if (mxBean.isThreadCpuTimeSupported()) { + try { + return mxBean.getThreadCpuTime(thr.getId()); + } catch (UnsupportedOperationException e) { + } + } + return 0; } private class CallableStatement implements Callable { -- cgit v1.2.3 From 08a6d4b74555db6d01048fc7065eb1e2bfaf33bc Mon Sep 17 00:00:00 2001 From: David Srbecky Date: Wed, 24 Feb 2021 15:52:50 +0000 Subject: Revert "Upgrade external/junit to 4.13.2" Revert submission 1601635 Reason for revert: b/181123058 Reverted Changes: I8f5cd1266:Remove support for stuck threads Ifdb59336d:Remove DisableOnDebug (new in 4.12) as it is not s... I6abae5aed:Extra generic type information to aid certain java... I5ec909df6:Upgrade external/junit to 4.13.2 Change-Id: Idaddfc2039816a8d7b12c91fdd540b801ab854ff --- .../org/junit/internal/ArrayComparisonFailure.java | 13 +- .../internal/AssumptionViolatedException.java | 30 +-- src/main/java/org/junit/internal/Checks.java | 37 ---- src/main/java/org/junit/internal/Classes.java | 28 +-- .../org/junit/internal/ComparisonCriteria.java | 89 ++------ .../internal/SerializableMatcherDescription.java | 47 ----- .../internal/SerializableValueDescription.java | 38 ---- src/main/java/org/junit/internal/TextListener.java | 4 +- src/main/java/org/junit/internal/Throwables.java | 231 --------------------- .../builders/AllDefaultPossibilitiesBuilder.java | 11 - .../org/junit/internal/builders/JUnit4Builder.java | 6 +- .../internal/management/FakeRuntimeMXBean.java | 21 -- .../internal/management/FakeThreadMXBean.java | 27 --- .../internal/management/ManagementFactory.java | 77 ------- .../management/ReflectiveRuntimeMXBean.java | 61 ------ .../management/ReflectiveThreadMXBean.java | 92 -------- .../junit/internal/management/RuntimeMXBean.java | 14 -- .../junit/internal/management/ThreadMXBean.java | 17 -- .../matchers/StacktracePrintingMatcher.java | 9 +- .../internal/matchers/ThrowableCauseMatcher.java | 6 +- .../junit/internal/matchers/TypeSafeMatcher.java | 2 +- .../org/junit/internal/requests/ClassRequest.java | 41 ++-- .../org/junit/internal/requests/FilterRequest.java | 2 +- .../junit/internal/requests/MemoizingRequest.java | 30 --- .../junit/internal/requests/OrderingRequest.java | 29 --- .../internal/runners/ErrorReportingRunner.java | 50 ++--- .../internal/runners/InitializationError.java | 2 +- .../junit/internal/runners/JUnit38ClassRunner.java | 22 +- .../junit/internal/runners/MethodValidator.java | 2 +- .../java/org/junit/internal/runners/TestClass.java | 2 +- .../internal/runners/model/EachTestNotifier.java | 23 -- .../internal/runners/rules/ValidationError.java | 3 - .../runners/statements/ExpectException.java | 4 +- .../internal/runners/statements/FailOnTimeout.java | 155 +------------- .../internal/runners/statements/RunAfters.java | 9 +- .../internal/runners/statements/RunBefores.java | 9 +- 36 files changed, 78 insertions(+), 1165 deletions(-) delete mode 100644 src/main/java/org/junit/internal/Checks.java delete mode 100644 src/main/java/org/junit/internal/SerializableMatcherDescription.java delete mode 100644 src/main/java/org/junit/internal/SerializableValueDescription.java delete mode 100644 src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java delete mode 100644 src/main/java/org/junit/internal/management/FakeThreadMXBean.java delete mode 100644 src/main/java/org/junit/internal/management/ManagementFactory.java delete mode 100644 src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java delete mode 100644 src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java delete mode 100644 src/main/java/org/junit/internal/management/RuntimeMXBean.java delete mode 100644 src/main/java/org/junit/internal/management/ThreadMXBean.java delete mode 100644 src/main/java/org/junit/internal/requests/MemoizingRequest.java delete mode 100644 src/main/java/org/junit/internal/requests/OrderingRequest.java (limited to 'src/main/java/org/junit/internal') diff --git a/src/main/java/org/junit/internal/ArrayComparisonFailure.java b/src/main/java/org/junit/internal/ArrayComparisonFailure.java index d300e7e..8627d6e 100644 --- a/src/main/java/org/junit/internal/ArrayComparisonFailure.java +++ b/src/main/java/org/junit/internal/ArrayComparisonFailure.java @@ -16,12 +16,11 @@ public class ArrayComparisonFailure extends AssertionError { /* * We have to use the f prefix until the next major release to ensure - * serialization compatibility. - * See https://github.com/junit-team/junit4/issues/976 + * serialization compatibility. + * See https://github.com/junit-team/junit/issues/976 */ private final List fIndices = new ArrayList(); private final String fMessage; - private final AssertionError fCause; /** * Construct a new ArrayComparisonFailure with an error text and the array's @@ -33,8 +32,7 @@ public class ArrayComparisonFailure extends AssertionError { */ public ArrayComparisonFailure(String message, AssertionError cause, int index) { this.fMessage = message; - this.fCause = cause; - initCause(fCause); + initCause(cause); addDimension(index); } @@ -42,11 +40,6 @@ public class ArrayComparisonFailure extends AssertionError { fIndices.add(0, index); } - @Override - public synchronized Throwable getCause() { - return super.getCause() == null ? fCause : super.getCause(); - } - @Override public String getMessage() { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/org/junit/internal/AssumptionViolatedException.java b/src/main/java/org/junit/internal/AssumptionViolatedException.java index 0e79b56..880d73f 100644 --- a/src/main/java/org/junit/internal/AssumptionViolatedException.java +++ b/src/main/java/org/junit/internal/AssumptionViolatedException.java @@ -1,8 +1,5 @@ package org.junit.internal; -import java.io.IOException; -import java.io.ObjectOutputStream; - import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.SelfDescribing; @@ -21,7 +18,7 @@ public class AssumptionViolatedException extends RuntimeException implements Sel /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit4/issues/976 + * See https://github.com/junit-team/junit/issues/976 */ private final String fAssumption; private final boolean fValueMatcher; @@ -111,29 +108,4 @@ public class AssumptionViolatedException extends RuntimeException implements Sel } } } - - /** - * Override default Java object serialization to correctly deal with potentially unserializable matchers or values. - * By not implementing readObject, we assure ourselves of backwards compatibility and compatibility with the - * standard way of Java serialization. - * - * @param objectOutputStream The outputStream to write our representation to - * @throws IOException When serialization fails - */ - private void writeObject(ObjectOutputStream objectOutputStream) throws IOException { - ObjectOutputStream.PutField putField = objectOutputStream.putFields(); - putField.put("fAssumption", fAssumption); - putField.put("fValueMatcher", fValueMatcher); - - // We have to wrap the matcher into a serializable form. - putField.put("fMatcher", SerializableMatcherDescription.asSerializableMatcher(fMatcher)); - - // We have to wrap the value inside a non-String class (instead of serializing the String value directly) as - // A Description will handle a String and non-String object differently (1st is surrounded by '"' while the - // latter will be surrounded by '<' '>'. Wrapping it makes sure that the description of a serialized and - // non-serialized instance produce the exact same description - putField.put("fValue", SerializableValueDescription.asSerializableValue(fValue)); - - objectOutputStream.writeFields(); - } } diff --git a/src/main/java/org/junit/internal/Checks.java b/src/main/java/org/junit/internal/Checks.java deleted file mode 100644 index 9724947..0000000 --- a/src/main/java/org/junit/internal/Checks.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.junit.internal; - -/** @since 4.13 */ -public final class Checks { - - private Checks() {} - - /** - * Checks that the given value is not {@code null}. - * - * @param value object reference to check - * @return the passed-in value, if not {@code null} - * @throws NullPointerException if {@code value} is {@code null} - */ - public static T notNull(T value) { - if (value == null) { - throw new NullPointerException(); - } - return value; - } - - /** - * Checks that the given value is not {@code null}, using the given message - * as the exception message if an exception is thrown. - * - * @param value object reference to check - * @param message message to use if {@code value} is {@code null} - * @return the passed-in value, if not {@code null} - * @throws NullPointerException if {@code value} is {@code null} - */ - public static T notNull(T value, String message) { - if (value == null) { - throw new NullPointerException(message); - } - return value; - } -} diff --git a/src/main/java/org/junit/internal/Classes.java b/src/main/java/org/junit/internal/Classes.java index e8404f6..154603d 100644 --- a/src/main/java/org/junit/internal/Classes.java +++ b/src/main/java/org/junit/internal/Classes.java @@ -6,39 +6,13 @@ import static java.lang.Thread.currentThread; * Miscellaneous functions dealing with classes. */ public class Classes { - - /** - * Do not instantiate. - * @deprecated will be private soon. - */ - @Deprecated - public Classes() { - } - /** * Returns Class.forName for {@code className} using the current thread's class loader. - * If the current thread does not have a class loader, falls back to the class loader for - * {@link Classes}. * * @param className Name of the class. * @throws ClassNotFoundException */ public static Class getClass(String className) throws ClassNotFoundException { - return getClass(className, Classes.class); - } - - /** - * Returns Class.forName for {@code className} using the current thread's class loader. - * If the current thread does not have a class loader, falls back to the class loader for the - * passed-in class. - * - * @param className Name of the class. - * @param callingClass Class that is requesting a the class - * @throws ClassNotFoundException - * @since 4.13 - */ - public static Class getClass(String className, Class callingClass) throws ClassNotFoundException { - ClassLoader classLoader = currentThread().getContextClassLoader(); - return Class.forName(className, true, classLoader == null ? callingClass.getClassLoader() : classLoader); + return Class.forName(className, true, currentThread().getContextClassLoader()); } } diff --git a/src/main/java/org/junit/internal/ComparisonCriteria.java b/src/main/java/org/junit/internal/ComparisonCriteria.java index ed1c674..e6d49a4 100644 --- a/src/main/java/org/junit/internal/ComparisonCriteria.java +++ b/src/main/java/org/junit/internal/ComparisonCriteria.java @@ -25,11 +25,6 @@ public abstract class ComparisonCriteria { */ public void arrayEquals(String message, Object expecteds, Object actuals) throws ArrayComparisonFailure { - arrayEquals(message, expecteds, actuals, true); - } - - private void arrayEquals(String message, Object expecteds, Object actuals, boolean outer) - throws ArrayComparisonFailure { if (expecteds == actuals || Arrays.deepEquals(new Object[] {expecteds}, new Object[] {actuals})) { // The reflection-based loop below is potentially very slow, especially for primitive @@ -39,37 +34,19 @@ public abstract class ComparisonCriteria { } String header = message == null ? "" : message + ": "; - // Only include the user-provided message in the outer exception. - String exceptionMessage = outer ? header : ""; - - if (expecteds == null) { - Assert.fail(exceptionMessage + "expected array was null"); - } - if (actuals == null) { - Assert.fail(exceptionMessage + "actual array was null"); - } - - int actualsLength = Array.getLength(actuals); - int expectedsLength = Array.getLength(expecteds); - if (actualsLength != expectedsLength) { - header += "array lengths differed, expected.length=" - + expectedsLength + " actual.length=" + actualsLength + "; "; - } - int prefixLength = Math.min(actualsLength, expectedsLength); + int expectedsLength = assertArraysAreSameLength(expecteds, + actuals, header); - for (int i = 0; i < prefixLength; i++) { + for (int i = 0; i < expectedsLength; i++) { Object expected = Array.get(expecteds, i); Object actual = Array.get(actuals, i); if (isArray(expected) && isArray(actual)) { try { - arrayEquals(message, expected, actual, false); + arrayEquals(message, expected, actual); } catch (ArrayComparisonFailure e) { e.addDimension(i); throw e; - } catch (AssertionError e) { - // Array lengths differed. - throw new ArrayComparisonFailure(header, e, i); } } else { try { @@ -79,53 +56,27 @@ public abstract class ComparisonCriteria { } } } - - if (actualsLength != expectedsLength) { - Object expected = getToStringableArrayElement(expecteds, expectedsLength, prefixLength); - Object actual = getToStringableArrayElement(actuals, actualsLength, prefixLength); - try { - Assert.assertEquals(expected, actual); - } catch (AssertionError e) { - throw new ArrayComparisonFailure(header, e, prefixLength); - } - } } - private static final Object END_OF_ARRAY_SENTINEL = objectWithToString("end of array"); - - private Object getToStringableArrayElement(Object array, int length, int index) { - if (index < length) { - Object element = Array.get(array, index); - if (isArray(element)) { - return objectWithToString(componentTypeName(element.getClass()) + "[" + Array.getLength(element) + "]"); - } else { - return element; - } - } else { - return END_OF_ARRAY_SENTINEL; - } - } - - private static Object objectWithToString(final String string) { - return new Object() { - @Override - public String toString() { - return string; - } - }; + private boolean isArray(Object expected) { + return expected != null && expected.getClass().isArray(); } - private String componentTypeName(Class arrayClass) { - Class componentType = arrayClass.getComponentType(); - if (componentType.isArray()) { - return componentTypeName(componentType) + "[]"; - } else { - return componentType.getName(); + private int assertArraysAreSameLength(Object expecteds, + Object actuals, String header) { + if (expecteds == null) { + Assert.fail(header + "expected array was null"); } - } - - private boolean isArray(Object expected) { - return expected != null && expected.getClass().isArray(); + if (actuals == null) { + Assert.fail(header + "actual array was null"); + } + int actualsLength = Array.getLength(actuals); + int expectedsLength = Array.getLength(expecteds); + if (actualsLength != expectedsLength) { + Assert.fail(header + "array lengths differed, expected.length=" + + expectedsLength + " actual.length=" + actualsLength); + } + return expectedsLength; } protected abstract void assertElementsEqual(Object expected, Object actual); diff --git a/src/main/java/org/junit/internal/SerializableMatcherDescription.java b/src/main/java/org/junit/internal/SerializableMatcherDescription.java deleted file mode 100644 index e036557..0000000 --- a/src/main/java/org/junit/internal/SerializableMatcherDescription.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.junit.internal; - -import java.io.Serializable; - -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.StringDescription; - -/** - * This class exists solely to provide a serializable description of a matcher to be serialized as a field in - * {@link AssumptionViolatedException}. Being a {@link Throwable}, it is required to be {@link Serializable}, but most - * implementations of {@link Matcher} are not. This class works around that limitation as - * {@link AssumptionViolatedException} only every uses the description of the {@link Matcher}, while still retaining - * backwards compatibility with classes compiled against its class signature before 4.14 and/or deserialization of - * previously serialized instances. - */ -class SerializableMatcherDescription extends BaseMatcher implements Serializable { - - private final String matcherDescription; - - private SerializableMatcherDescription(Matcher matcher) { - matcherDescription = StringDescription.asString(matcher); - } - - public boolean matches(Object o) { - throw new UnsupportedOperationException("This Matcher implementation only captures the description"); - } - - public void describeTo(Description description) { - description.appendText(matcherDescription); - } - - /** - * Factory method that checks to see if the matcher is already serializable. - * @param matcher the matcher to make serializable - * @return The provided matcher if it is null or already serializable, - * the SerializableMatcherDescription representation of it if it is not. - */ - static Matcher asSerializableMatcher(Matcher matcher) { - if (matcher == null || matcher instanceof Serializable) { - return matcher; - } else { - return new SerializableMatcherDescription(matcher); - } - } -} diff --git a/src/main/java/org/junit/internal/SerializableValueDescription.java b/src/main/java/org/junit/internal/SerializableValueDescription.java deleted file mode 100644 index 4d055d7..0000000 --- a/src/main/java/org/junit/internal/SerializableValueDescription.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.junit.internal; - -import java.io.Serializable; - -/** - * This class exists solely to provide a serializable description of a value to be serialized as a field in - * {@link AssumptionViolatedException}. Being a {@link Throwable}, it is required to be {@link Serializable}, but a - * value of type Object provides no guarantee to be serializable. This class works around that limitation as - * {@link AssumptionViolatedException} only every uses the string representation of the value, while still retaining - * backwards compatibility with classes compiled against its class signature before 4.14 and/or deserialization of - * previously serialized instances. - */ -class SerializableValueDescription implements Serializable { - private final String value; - - private SerializableValueDescription(Object value) { - this.value = String.valueOf(value); - } - - /** - * Factory method that checks to see if the value is already serializable. - * @param value the value to make serializable - * @return The provided value if it is null or already serializable, - * the SerializableValueDescription representation of it if it is not. - */ - static Object asSerializableValue(Object value) { - if (value == null || value instanceof Serializable) { - return value; - } else { - return new SerializableValueDescription(value); - } - } - - @Override - public String toString() { - return value; - } -} diff --git a/src/main/java/org/junit/internal/TextListener.java b/src/main/java/org/junit/internal/TextListener.java index d548aeb..9aa56c7 100644 --- a/src/main/java/org/junit/internal/TextListener.java +++ b/src/main/java/org/junit/internal/TextListener.java @@ -58,7 +58,7 @@ public class TextListener extends RunListener { protected void printFailures(Result result) { List failures = result.getFailures(); - if (failures.isEmpty()) { + if (failures.size() == 0) { return; } if (failures.size() == 1) { @@ -74,7 +74,7 @@ public class TextListener extends RunListener { protected void printFailure(Failure each, String prefix) { getWriter().println(prefix + ") " + each.getTestHeader()); - getWriter().print(each.getTrimmedTrace()); + getWriter().print(each.getTrace()); } protected void printFooter(Result result) { diff --git a/src/main/java/org/junit/internal/Throwables.java b/src/main/java/org/junit/internal/Throwables.java index 3f0f7a3..86dceef 100644 --- a/src/main/java/org/junit/internal/Throwables.java +++ b/src/main/java/org/junit/internal/Throwables.java @@ -1,17 +1,5 @@ package org.junit.internal; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringReader; -import java.io.StringWriter; -import java.lang.reflect.Method; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - /** * Miscellaneous functions dealing with {@code Throwable}. * @@ -51,223 +39,4 @@ public final class Throwables { private static void rethrow(Throwable e) throws T { throw (T) e; } - - /** - * Returns the stacktrace of the given Throwable as a String. - * - * @since 4.13 - */ - public static String getStacktrace(Throwable exception) { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - exception.printStackTrace(writer); - return stringWriter.toString(); - } - - /** - * Gets a trimmed version of the stack trace of the given exception. Stack trace - * elements that are below the test method are filtered out. - * - * @return a trimmed stack trace, or the original trace if trimming wasn't possible - */ - public static String getTrimmedStackTrace(Throwable exception) { - List trimmedStackTraceLines = getTrimmedStackTraceLines(exception); - if (trimmedStackTraceLines.isEmpty()) { - return getFullStackTrace(exception); - } - - StringBuilder result = new StringBuilder(exception.toString()); - appendStackTraceLines(trimmedStackTraceLines, result); - appendStackTraceLines(getCauseStackTraceLines(exception), result); - return result.toString(); - } - - private static List getTrimmedStackTraceLines(Throwable exception) { - List stackTraceElements = Arrays.asList(exception.getStackTrace()); - int linesToInclude = stackTraceElements.size(); - - State state = State.PROCESSING_OTHER_CODE; - for (StackTraceElement stackTraceElement : asReversedList(stackTraceElements)) { - state = state.processStackTraceElement(stackTraceElement); - if (state == State.DONE) { - List trimmedLines = new ArrayList(linesToInclude + 2); - trimmedLines.add(""); - for (StackTraceElement each : stackTraceElements.subList(0, linesToInclude)) { - trimmedLines.add("\tat " + each); - } - if (exception.getCause() != null) { - trimmedLines.add("\t... " + (stackTraceElements.size() - trimmedLines.size()) + " trimmed"); - } - return trimmedLines; - } - linesToInclude--; - } - return Collections.emptyList(); - } - - private static final Method getSuppressed = initGetSuppressed(); - - private static Method initGetSuppressed() { - try { - return Throwable.class.getMethod("getSuppressed"); - } catch (Throwable e) { - return null; - } - } - - private static boolean hasSuppressed(Throwable exception) { - if (getSuppressed == null) { - return false; - } - try { - Throwable[] suppressed = (Throwable[]) getSuppressed.invoke(exception); - return suppressed.length != 0; - } catch (Throwable e) { - return false; - } - } - - private static List getCauseStackTraceLines(Throwable exception) { - if (exception.getCause() != null || hasSuppressed(exception)) { - String fullTrace = getFullStackTrace(exception); - BufferedReader reader = new BufferedReader( - new StringReader(fullTrace.substring(exception.toString().length()))); - List causedByLines = new ArrayList(); - - try { - String line; - while ((line = reader.readLine()) != null) { - if (line.startsWith("Caused by: ") || line.trim().startsWith("Suppressed: ")) { - causedByLines.add(line); - while ((line = reader.readLine()) != null) { - causedByLines.add(line); - } - return causedByLines; - } - } - } catch (IOException e) { - // We should never get here, because we are reading from a StringReader - } - } - - return Collections.emptyList(); - } - - private static String getFullStackTrace(Throwable exception) { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - exception.printStackTrace(writer); - return stringWriter.toString(); - } - - private static void appendStackTraceLines( - List stackTraceLines, StringBuilder destBuilder) { - for (String stackTraceLine : stackTraceLines) { - destBuilder.append(String.format("%s%n", stackTraceLine)); - } - } - - private static List asReversedList(final List list) { - return new AbstractList() { - - @Override - public T get(int index) { - return list.get(list.size() - index - 1); - } - - @Override - public int size() { - return list.size(); - } - }; - } - - private enum State { - PROCESSING_OTHER_CODE { - @Override public State processLine(String methodName) { - if (isTestFrameworkMethod(methodName)) { - return PROCESSING_TEST_FRAMEWORK_CODE; - } - return this; - } - }, - PROCESSING_TEST_FRAMEWORK_CODE { - @Override public State processLine(String methodName) { - if (isReflectionMethod(methodName)) { - return PROCESSING_REFLECTION_CODE; - } else if (isTestFrameworkMethod(methodName)) { - return this; - } - return PROCESSING_OTHER_CODE; - } - }, - PROCESSING_REFLECTION_CODE { - @Override public State processLine(String methodName) { - if (isReflectionMethod(methodName)) { - return this; - } else if (isTestFrameworkMethod(methodName)) { - // This is here to handle TestCase.runBare() calling TestCase.runTest(). - return PROCESSING_TEST_FRAMEWORK_CODE; - } - return DONE; - } - }, - DONE { - @Override public State processLine(String methodName) { - return this; - } - }; - - /** Processes a stack trace element method name, possibly moving to a new state. */ - protected abstract State processLine(String methodName); - - /** Processes a stack trace element, possibly moving to a new state. */ - public final State processStackTraceElement(StackTraceElement element) { - return processLine(element.getClassName() + "." + element.getMethodName() + "()"); - } - } - - private static final String[] TEST_FRAMEWORK_METHOD_NAME_PREFIXES = { - "org.junit.runner.", - "org.junit.runners.", - "org.junit.experimental.runners.", - "org.junit.internal.", - "junit.extensions", - "junit.framework", - "junit.runner", - "junit.textui", - }; - - private static final String[] TEST_FRAMEWORK_TEST_METHOD_NAME_PREFIXES = { - "org.junit.internal.StackTracesTest", - }; - - private static boolean isTestFrameworkMethod(String methodName) { - return isMatchingMethod(methodName, TEST_FRAMEWORK_METHOD_NAME_PREFIXES) && - !isMatchingMethod(methodName, TEST_FRAMEWORK_TEST_METHOD_NAME_PREFIXES); - } - - private static final String[] REFLECTION_METHOD_NAME_PREFIXES = { - "sun.reflect.", - "java.lang.reflect.", - "jdk.internal.reflect.", - "org.junit.rules.RunRules.(", - "org.junit.rules.RunRules.applyAll(", // calls TestRules - "org.junit.runners.RuleContainer.apply(", // calls MethodRules & TestRules - "junit.framework.TestCase.runBare(", // runBare() directly calls setUp() and tearDown() - }; - - private static boolean isReflectionMethod(String methodName) { - return isMatchingMethod(methodName, REFLECTION_METHOD_NAME_PREFIXES); - } - - private static boolean isMatchingMethod(String methodName, String[] methodNamePrefixes) { - for (String methodNamePrefix : methodNamePrefixes) { - if (methodName.startsWith(methodNamePrefix)) { - return true; - } - } - - return false; - } } diff --git a/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java index 8704a54..d86ec95 100644 --- a/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java +++ b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java @@ -9,17 +9,6 @@ import org.junit.runners.model.RunnerBuilder; public class AllDefaultPossibilitiesBuilder extends RunnerBuilder { private final boolean canUseSuiteMethod; - /** - * @since 4.13 - */ - public AllDefaultPossibilitiesBuilder() { - canUseSuiteMethod = true; - } - - /** - * @deprecated used {@link #AllDefaultPossibilitiesBuilder()}. - */ - @Deprecated public AllDefaultPossibilitiesBuilder(boolean canUseSuiteMethod) { this.canUseSuiteMethod = canUseSuiteMethod; } diff --git a/src/main/java/org/junit/internal/builders/JUnit4Builder.java b/src/main/java/org/junit/internal/builders/JUnit4Builder.java index 7959e75..6a00678 100644 --- a/src/main/java/org/junit/internal/builders/JUnit4Builder.java +++ b/src/main/java/org/junit/internal/builders/JUnit4Builder.java @@ -1,12 +1,12 @@ package org.junit.internal.builders; import org.junit.runner.Runner; -import org.junit.runners.JUnit4; +import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.RunnerBuilder; public class JUnit4Builder extends RunnerBuilder { @Override public Runner runnerForClass(Class testClass) throws Throwable { - return new JUnit4(testClass); + return new BlockJUnit4ClassRunner(testClass); } -} +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java b/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java deleted file mode 100644 index 477b150..0000000 --- a/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.junit.internal.management; - -import java.util.Collections; -import java.util.List; - -/** - * No-op implementation of RuntimeMXBean when the platform doesn't provide it. - */ -class FakeRuntimeMXBean implements RuntimeMXBean { - - /** - * {@inheritDoc} - * - *

Always returns an empty list. - */ - public List getInputArguments() { - return Collections.emptyList(); - } - -} - diff --git a/src/main/java/org/junit/internal/management/FakeThreadMXBean.java b/src/main/java/org/junit/internal/management/FakeThreadMXBean.java deleted file mode 100644 index 893f2e3..0000000 --- a/src/main/java/org/junit/internal/management/FakeThreadMXBean.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.junit.internal.management; - -/** - * No-op implementation of ThreadMXBean when the platform doesn't provide it. - */ -final class FakeThreadMXBean implements ThreadMXBean { - - /** - * {@inheritDoc} - * - *

Always throws an {@link UnsupportedOperationException} - */ - public long getThreadCpuTime(long id) { - throw new UnsupportedOperationException(); - } - - /** - * {@inheritDoc} - * - *

Always returns false. - */ - public boolean isThreadCpuTimeSupported() { - return false; - } - -} - diff --git a/src/main/java/org/junit/internal/management/ManagementFactory.java b/src/main/java/org/junit/internal/management/ManagementFactory.java deleted file mode 100644 index 5be1447..0000000 --- a/src/main/java/org/junit/internal/management/ManagementFactory.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.junit.internal.management; - -import org.junit.internal.Classes; - -import java.lang.reflect.InvocationTargetException; - -/** - * Reflective wrapper around {@link java.lang.management.ManagementFactory} - */ -public class ManagementFactory { - private static final class FactoryHolder { - private static final Class MANAGEMENT_FACTORY_CLASS; - - static { - Class managementFactoryClass = null; - try { - managementFactoryClass = Classes.getClass("java.lang.management.ManagementFactory"); - } catch (ClassNotFoundException e) { - // do nothing, managementFactoryClass will be none on failure - } - MANAGEMENT_FACTORY_CLASS = managementFactoryClass; - } - - static Object getBeanObject(String methodName) { - if (MANAGEMENT_FACTORY_CLASS != null) { - try { - return MANAGEMENT_FACTORY_CLASS.getMethod(methodName).invoke(null); - } catch (IllegalAccessException e) { - // fallthrough - } catch (IllegalArgumentException e) { - // fallthrough - } catch (InvocationTargetException e) { - // fallthrough - } catch (NoSuchMethodException e) { - // fallthrough - } catch (SecurityException e) { - // fallthrough - } - } - return null; - } - } - - private static final class RuntimeHolder { - private static final RuntimeMXBean RUNTIME_MX_BEAN = - getBean(FactoryHolder.getBeanObject("getRuntimeMXBean")); - - private static final RuntimeMXBean getBean(Object runtimeMxBean) { - return runtimeMxBean != null - ? new ReflectiveRuntimeMXBean(runtimeMxBean) : new FakeRuntimeMXBean(); - } - } - - private static final class ThreadHolder { - private static final ThreadMXBean THREAD_MX_BEAN = - getBean(FactoryHolder.getBeanObject("getThreadMXBean")); - - private static final ThreadMXBean getBean(Object threadMxBean) { - return threadMxBean != null - ? new ReflectiveThreadMXBean(threadMxBean) : new FakeThreadMXBean(); - } - } - - /** - * @see java.lang.management.ManagementFactory#getRuntimeMXBean() - */ - public static RuntimeMXBean getRuntimeMXBean() { - return RuntimeHolder.RUNTIME_MX_BEAN; - } - - /** - * @see java.lang.management.ManagementFactory#getThreadMXBean() - */ - public static ThreadMXBean getThreadMXBean() { - return ThreadHolder.THREAD_MX_BEAN; - } -} diff --git a/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java b/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java deleted file mode 100644 index 289587a..0000000 --- a/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.junit.internal.management; - -import org.junit.internal.Classes; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; - -/** - * Implementation of {@link RuntimeMXBean} using the JVM reflectively. - */ -final class ReflectiveRuntimeMXBean implements RuntimeMXBean { - private final Object runtimeMxBean; - - private static final class Holder { - private static final Method getInputArgumentsMethod; - static { - Method inputArguments = null; - try { - Class threadMXBeanClass = Classes.getClass("java.lang.management.RuntimeMXBean"); - inputArguments = threadMXBeanClass.getMethod("getInputArguments"); - } catch (ClassNotFoundException e) { - // do nothing, input arguments will be null on failure - } catch (NoSuchMethodException e) { - // do nothing, input arguments will be null on failure - } catch (SecurityException e) { - // do nothing, input arguments will be null on failure - } - getInputArgumentsMethod = inputArguments; - } - } - - ReflectiveRuntimeMXBean(Object runtimeMxBean) { - super(); - this.runtimeMxBean = runtimeMxBean; - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public List getInputArguments() { - if (Holder.getInputArgumentsMethod != null) { - try { - return (List) Holder.getInputArgumentsMethod.invoke(runtimeMxBean); - } catch (ClassCastException e) { // no multi-catch with source level 6 - // fallthrough - } catch (IllegalAccessException e) { - // fallthrough - } catch (IllegalArgumentException e) { - // fallthrough - } catch (InvocationTargetException e) { - // fallthrough - } - } - return Collections.emptyList(); - } - -} - diff --git a/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java b/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java deleted file mode 100644 index bc741be..0000000 --- a/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.junit.internal.management; - -import org.junit.internal.Classes; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Implementation of {@link ThreadMXBean} using the JVM reflectively. - */ -final class ReflectiveThreadMXBean implements ThreadMXBean { - private final Object threadMxBean; - - - private static final class Holder { - static final Method getThreadCpuTimeMethod; - static final Method isThreadCpuTimeSupportedMethod; - - private static final String FAILURE_MESSAGE = "Unable to access ThreadMXBean"; - - static { - Method threadCpuTime = null; - Method threadCpuTimeSupported = null; - try { - Class threadMXBeanClass = Classes.getClass("java.lang.management.ThreadMXBean"); - threadCpuTime = threadMXBeanClass.getMethod("getThreadCpuTime", long.class); - threadCpuTimeSupported = threadMXBeanClass.getMethod("isThreadCpuTimeSupported"); - } catch (ClassNotFoundException e) { - // do nothing, the methods will be null on failure - } catch (NoSuchMethodException e) { - // do nothing, the methods will be null on failure - } catch (SecurityException e) { - // do nothing, the methods will be null on failure - } - getThreadCpuTimeMethod = threadCpuTime; - isThreadCpuTimeSupportedMethod = threadCpuTimeSupported; - } - } - - ReflectiveThreadMXBean(Object threadMxBean) { - super(); - this.threadMxBean = threadMxBean; - } - - /** - * {@inheritDoc} - */ - public long getThreadCpuTime(long id) { - if (Holder.getThreadCpuTimeMethod != null) { - Exception error = null; - try { - return (Long) Holder.getThreadCpuTimeMethod.invoke(threadMxBean, id); - } catch (ClassCastException e) { - error = e; - // fallthrough - } catch (IllegalAccessException e) { - error = e; - // fallthrough - } catch (IllegalArgumentException e) { - error = e; - // fallthrough - } catch (InvocationTargetException e) { - error = e; - // fallthrough - } - throw new UnsupportedOperationException(Holder.FAILURE_MESSAGE, error); - } - throw new UnsupportedOperationException(Holder.FAILURE_MESSAGE); - } - - /** - * {@inheritDoc} - */ - public boolean isThreadCpuTimeSupported() { - if (Holder.isThreadCpuTimeSupportedMethod != null) { - try { - return (Boolean) Holder.isThreadCpuTimeSupportedMethod.invoke(threadMxBean); - } catch (ClassCastException e) { - // fallthrough - } catch (IllegalAccessException e) { - // fallthrough - } catch (IllegalArgumentException e) { - // fallthrough - } catch (InvocationTargetException e) { - // fallthrough - } - } - return false; - } - -} - diff --git a/src/main/java/org/junit/internal/management/RuntimeMXBean.java b/src/main/java/org/junit/internal/management/RuntimeMXBean.java deleted file mode 100644 index 84f8861..0000000 --- a/src/main/java/org/junit/internal/management/RuntimeMXBean.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.junit.internal.management; - -import java.util.List; - -/** - * Wrapper for {@link java.lang.management.RuntimeMXBean}. - */ -public interface RuntimeMXBean { - - /** - * @see java.lang.management.RuntimeMXBean#getInputArguments() - */ - List getInputArguments(); -} diff --git a/src/main/java/org/junit/internal/management/ThreadMXBean.java b/src/main/java/org/junit/internal/management/ThreadMXBean.java deleted file mode 100644 index f9225c9..0000000 --- a/src/main/java/org/junit/internal/management/ThreadMXBean.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.junit.internal.management; - -/** - * Wrapper for {@link java.lang.management.ThreadMXBean}. - */ -public interface ThreadMXBean { - /** - * @see java.lang.management.ThreadMXBean#getThreadCpuTime(long) - */ - long getThreadCpuTime(long id); - - /** - * @see java.lang.management.ThreadMXBean#isThreadCpuTimeSupported() - */ - boolean isThreadCpuTimeSupported(); -} - diff --git a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java index 93a6827..5d45ba3 100644 --- a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java +++ b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java @@ -1,11 +1,12 @@ package org.junit.internal.matchers; +import java.io.PrintWriter; +import java.io.StringWriter; + import org.hamcrest.Description; import org.hamcrest.Factory; import org.hamcrest.Matcher; -import org.junit.internal.Throwables; - /** * A matcher that delegates to throwableMatcher and in addition appends the * stacktrace of the actual Throwable in case of a mismatch. @@ -36,7 +37,9 @@ public class StacktracePrintingMatcher extends } private String readStacktrace(Throwable throwable) { - return Throwables.getStacktrace(throwable); + StringWriter stringWriter = new StringWriter(); + throwable.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); } @Factory diff --git a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java index 6e2ff5e..22ce8bd 100644 --- a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java +++ b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java @@ -14,9 +14,9 @@ import org.hamcrest.TypeSafeMatcher; public class ThrowableCauseMatcher extends TypeSafeMatcher { - private final Matcher causeMatcher; + private final Matcher causeMatcher; - public ThrowableCauseMatcher(Matcher causeMatcher) { + public ThrowableCauseMatcher(Matcher causeMatcher) { this.causeMatcher = causeMatcher; } @@ -44,7 +44,7 @@ public class ThrowableCauseMatcher extends * @param type of the outer exception */ @Factory - public static Matcher hasCause(final Matcher matcher) { + public static Matcher hasCause(final Matcher matcher) { return new ThrowableCauseMatcher(matcher); } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java index fb25982..4e2cc12 100644 --- a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java +++ b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java @@ -40,7 +40,7 @@ public abstract class TypeSafeMatcher extends BaseMatcher { } private static boolean isMatchesSafelyMethod(Method method) { - return "matchesSafely".equals(method.getName()) + return method.getName().equals("matchesSafely") && method.getParameterTypes().length == 1 && !method.isSynthetic(); } diff --git a/src/main/java/org/junit/internal/requests/ClassRequest.java b/src/main/java/org/junit/internal/requests/ClassRequest.java index d60e360..3d6b100 100644 --- a/src/main/java/org/junit/internal/requests/ClassRequest.java +++ b/src/main/java/org/junit/internal/requests/ClassRequest.java @@ -1,18 +1,20 @@ package org.junit.internal.requests; import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; -import org.junit.internal.builders.SuiteMethodBuilder; +import org.junit.runner.Request; import org.junit.runner.Runner; -import org.junit.runners.model.RunnerBuilder; -public class ClassRequest extends MemoizingRequest { +public class ClassRequest extends Request { + private final Object runnerLock = new Object(); + /* * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses * reflection to access this field. See - * https://github.com/junit-team/junit4/issues/960 + * https://github.com/junit-team/junit/issues/960 */ private final Class fTestClass; private final boolean canUseSuiteMethod; + private volatile Runner runner; public ClassRequest(Class testClass, boolean canUseSuiteMethod) { this.fTestClass = testClass; @@ -24,31 +26,14 @@ public class ClassRequest extends MemoizingRequest { } @Override - protected Runner createRunner() { - return new CustomAllDefaultPossibilitiesBuilder().safeRunnerForClass(fTestClass); - } - - private class CustomAllDefaultPossibilitiesBuilder extends AllDefaultPossibilitiesBuilder { - - @Override - protected RunnerBuilder suiteMethodBuilder() { - return new CustomSuiteMethodBuilder(); - } - } - - /* - * Customization of {@link SuiteMethodBuilder} that prevents use of the - * suite method when creating a runner for fTestClass when canUseSuiteMethod - * is false. - */ - private class CustomSuiteMethodBuilder extends SuiteMethodBuilder { - - @Override - public Runner runnerForClass(Class testClass) throws Throwable { - if (testClass == fTestClass && !canUseSuiteMethod) { - return null; + public Runner getRunner() { + if (runner == null) { + synchronized (runnerLock) { + if (runner == null) { + runner = new AllDefaultPossibilitiesBuilder(canUseSuiteMethod).safeRunnerForClass(fTestClass); + } } - return super.runnerForClass(testClass); } + return runner; } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/requests/FilterRequest.java b/src/main/java/org/junit/internal/requests/FilterRequest.java index 5f00399..066cba3 100644 --- a/src/main/java/org/junit/internal/requests/FilterRequest.java +++ b/src/main/java/org/junit/internal/requests/FilterRequest.java @@ -14,7 +14,7 @@ public final class FilterRequest extends Request { /* * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses * reflection to access this field. See - * https://github.com/junit-team/junit4/issues/960 + * https://github.com/junit-team/junit/issues/960 */ private final Filter fFilter; diff --git a/src/main/java/org/junit/internal/requests/MemoizingRequest.java b/src/main/java/org/junit/internal/requests/MemoizingRequest.java deleted file mode 100644 index 191c230..0000000 --- a/src/main/java/org/junit/internal/requests/MemoizingRequest.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.junit.internal.requests; - -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.junit.runner.Request; -import org.junit.runner.Runner; - -abstract class MemoizingRequest extends Request { - private final Lock runnerLock = new ReentrantLock(); - private volatile Runner runner; - - @Override - public final Runner getRunner() { - if (runner == null) { - runnerLock.lock(); - try { - if (runner == null) { - runner = createRunner(); - } - } finally { - runnerLock.unlock(); - } - } - return runner; - } - - /** Creates the {@link Runner} to return from {@link #getRunner()}. Called at most once. */ - protected abstract Runner createRunner(); -} diff --git a/src/main/java/org/junit/internal/requests/OrderingRequest.java b/src/main/java/org/junit/internal/requests/OrderingRequest.java deleted file mode 100644 index 441e595..0000000 --- a/src/main/java/org/junit/internal/requests/OrderingRequest.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.junit.internal.requests; - -import org.junit.internal.runners.ErrorReportingRunner; -import org.junit.runner.Request; -import org.junit.runner.Runner; -import org.junit.runner.manipulation.InvalidOrderingException; -import org.junit.runner.manipulation.Ordering; - -/** @since 4.13 */ -public class OrderingRequest extends MemoizingRequest { - private final Request request; - private final Ordering ordering; - - public OrderingRequest(Request request, Ordering ordering) { - this.request = request; - this.ordering = ordering; - } - - @Override - protected Runner createRunner() { - Runner runner = request.getRunner(); - try { - ordering.apply(runner); - } catch (InvalidOrderingException e) { - return new ErrorReportingRunner(ordering.getClass(), e); - } - return runner; - } -} diff --git a/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java index f52abab..1d32beb 100644 --- a/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java +++ b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java @@ -1,44 +1,33 @@ package org.junit.internal.runners; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; import java.util.List; import org.junit.runner.Description; import org.junit.runner.Runner; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; -import org.junit.runners.model.InvalidTestClassError; import org.junit.runners.model.InitializationError; -import static java.util.Collections.singletonList; - public class ErrorReportingRunner extends Runner { private final List causes; - private final String classNames; + private final Class testClass; public ErrorReportingRunner(Class testClass, Throwable cause) { - this(cause, testClass); - } - - public ErrorReportingRunner(Throwable cause, Class... testClasses) { - if (testClasses == null || testClasses.length == 0) { - throw new NullPointerException("Test classes cannot be null or empty"); + if (testClass == null) { + throw new NullPointerException("Test class cannot be null"); } - for (Class testClass : testClasses) { - if (testClass == null) { - throw new NullPointerException("Test class cannot be null"); - } - } - classNames = getClassNames(testClasses); + this.testClass = testClass; causes = getCauses(cause); } - + @Override public Description getDescription() { - Description description = Description.createSuiteDescription(classNames); + Description description = Description.createSuiteDescription(testClass); for (Throwable each : causes) { - description.addChild(describeCause()); + description.addChild(describeCause(each)); } return description; } @@ -50,25 +39,11 @@ public class ErrorReportingRunner extends Runner { } } - private String getClassNames(Class... testClasses) { - final StringBuilder builder = new StringBuilder(); - for (Class testClass : testClasses) { - if (builder.length() != 0) { - builder.append(", "); - } - builder.append(testClass.getName()); - } - return builder.toString(); - } - @SuppressWarnings("deprecation") private List getCauses(Throwable cause) { if (cause instanceof InvocationTargetException) { return getCauses(cause.getCause()); } - if (cause instanceof InvalidTestClassError) { - return singletonList(cause); - } if (cause instanceof InitializationError) { return ((InitializationError) cause).getCauses(); } @@ -76,15 +51,16 @@ public class ErrorReportingRunner extends Runner { return ((org.junit.internal.runners.InitializationError) cause) .getCauses(); } - return singletonList(cause); + return Arrays.asList(cause); } - private Description describeCause() { - return Description.createTestDescription(classNames, "initializationError"); + private Description describeCause(Throwable child) { + return Description.createTestDescription(testClass, + "initializationError"); } private void runCause(Throwable child, RunNotifier notifier) { - Description description = describeCause(); + Description description = describeCause(child); notifier.fireTestStarted(description); notifier.fireTestFailure(new Failure(description, child)); notifier.fireTestFinished(description); diff --git a/src/main/java/org/junit/internal/runners/InitializationError.java b/src/main/java/org/junit/internal/runners/InitializationError.java index 484f58d..52065ec 100644 --- a/src/main/java/org/junit/internal/runners/InitializationError.java +++ b/src/main/java/org/junit/internal/runners/InitializationError.java @@ -15,7 +15,7 @@ public class InitializationError extends Exception { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit4/issues/976 + * See https://github.com/junit-team/junit/issues/976 */ private final List fErrors; diff --git a/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java index 0d51541..631fcf2 100644 --- a/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java +++ b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java @@ -1,8 +1,5 @@ package org.junit.internal.runners; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; - import junit.extensions.TestDecorator; import junit.framework.AssertionFailedError; import junit.framework.Test; @@ -15,16 +12,15 @@ import org.junit.runner.Description; import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.Filterable; -import org.junit.runner.manipulation.Orderer; -import org.junit.runner.manipulation.InvalidOrderingException; import org.junit.runner.manipulation.NoTestsRemainException; -import org.junit.runner.manipulation.Orderable; import org.junit.runner.manipulation.Sortable; import org.junit.runner.manipulation.Sorter; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; -public class JUnit38ClassRunner extends Runner implements Filterable, Orderable { +public class JUnit38ClassRunner extends Runner implements Filterable, Sortable { private static final class OldTestClassAdaptingListener implements TestListener { private final RunNotifier notifier; @@ -174,18 +170,6 @@ public class JUnit38ClassRunner extends Runner implements Filterable, Orderable } } - /** - * {@inheritDoc} - * - * @since 4.13 - */ - public void order(Orderer orderer) throws InvalidOrderingException { - if (getTest() instanceof Orderable) { - Orderable adapter = (Orderable) getTest(); - adapter.order(orderer); - } - } - private void setTest(Test test) { this.test = test; } diff --git a/src/main/java/org/junit/internal/runners/MethodValidator.java b/src/main/java/org/junit/internal/runners/MethodValidator.java index e656ee5..ba9c9d1 100644 --- a/src/main/java/org/junit/internal/runners/MethodValidator.java +++ b/src/main/java/org/junit/internal/runners/MethodValidator.java @@ -86,7 +86,7 @@ public class MethodValidator { } if (each.getReturnType() != Void.TYPE) { errors.add(new Exception("Method " + each.getName() - + "should have a return type of void")); + + " should be void")); } if (each.getParameterTypes().length != 0) { errors.add(new Exception("Method " + each.getName() diff --git a/src/main/java/org/junit/internal/runners/TestClass.java b/src/main/java/org/junit/internal/runners/TestClass.java index 6d24f4f..1abaeea 100644 --- a/src/main/java/org/junit/internal/runners/TestClass.java +++ b/src/main/java/org/junit/internal/runners/TestClass.java @@ -85,7 +85,7 @@ public class TestClass { } private List> getSuperClasses(Class testClass) { - List> results = new ArrayList>(); + ArrayList> results = new ArrayList>(); Class current = testClass; while (current != null) { results.add(current); diff --git a/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java index c5a0764..e094809 100644 --- a/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java +++ b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java @@ -45,27 +45,4 @@ public class EachTestNotifier { public void fireTestIgnored() { notifier.fireTestIgnored(description); } - - /** - * Calls {@link RunNotifier#fireTestSuiteStarted(Description)}, passing the - * {@link Description} that was passed to the {@code EachTestNotifier} constructor. - * This should be called when a test suite is about to be started. - * @see RunNotifier#fireTestSuiteStarted(Description) - * @since 4.13 - */ - public void fireTestSuiteStarted() { - notifier.fireTestSuiteStarted(description); - } - - /** - * Calls {@link RunNotifier#fireTestSuiteFinished(Description)}, passing the - * {@link Description} that was passed to the {@code EachTestNotifier} constructor. - * This should be called when a test suite has finished, whether the test suite succeeds - * or fails. - * @see RunNotifier#fireTestSuiteFinished(Description) - * @since 4.13 - */ - public void fireTestSuiteFinished() { - notifier.fireTestSuiteFinished(description); - } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/rules/ValidationError.java b/src/main/java/org/junit/internal/runners/rules/ValidationError.java index 31bd660..d1af8ae 100644 --- a/src/main/java/org/junit/internal/runners/rules/ValidationError.java +++ b/src/main/java/org/junit/internal/runners/rules/ValidationError.java @@ -5,9 +5,6 @@ import org.junit.runners.model.FrameworkMember; import java.lang.annotation.Annotation; class ValidationError extends Exception { - - private static final long serialVersionUID = 3176511008672645574L; - public ValidationError(FrameworkMember member, Class annotation, String suffix) { super(String.format("The @%s '%s' %s", annotation.getSimpleName(), member.getName(), suffix)); } diff --git a/src/main/java/org/junit/internal/runners/statements/ExpectException.java b/src/main/java/org/junit/internal/runners/statements/ExpectException.java index 9a2a952..d0636bd 100644 --- a/src/main/java/org/junit/internal/runners/statements/ExpectException.java +++ b/src/main/java/org/junit/internal/runners/statements/ExpectException.java @@ -19,9 +19,7 @@ public class ExpectException extends Statement { next.evaluate(); complete = true; } catch (AssumptionViolatedException e) { - if (!expected.isAssignableFrom(e.getClass())) { - throw e; - } + throw e; } catch (Throwable e) { if (!expected.isAssignableFrom(e.getClass())) { String message = "Unexpected exception, expected<" diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java index 9362cc1..9fad35b 100644 --- a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java +++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java @@ -1,8 +1,5 @@ package org.junit.internal.runners.statements; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -10,9 +7,6 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.junit.internal.management.ManagementFactory; -import org.junit.internal.management.ThreadMXBean; -import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; import org.junit.runners.model.TestTimedOutException; @@ -20,7 +14,6 @@ public class FailOnTimeout extends Statement { private final Statement originalStatement; private final TimeUnit timeUnit; private final long timeout; - private final boolean lookForStuckThread; /** * Returns a new builder for building an instance. @@ -47,7 +40,6 @@ public class FailOnTimeout extends Statement { originalStatement = statement; timeout = builder.timeout; timeUnit = builder.unit; - lookForStuckThread = builder.lookForStuckThread; } /** @@ -56,7 +48,6 @@ public class FailOnTimeout extends Statement { * @since 4.12 */ public static class Builder { - private boolean lookForStuckThread = false; private long timeout = 0; private TimeUnit unit = TimeUnit.SECONDS; @@ -88,20 +79,6 @@ public class FailOnTimeout extends Statement { return this; } - /** - * Specifies whether to look for a stuck thread. If a timeout occurs and this - * feature is enabled, the test will look for a thread that appears to be stuck - * and dump its backtrace. This feature is experimental. Behavior may change - * after the 4.12 release in response to feedback. - * - * @param enable {@code true} to enable the feature - * @return {@code this} for method chaining. - */ - public Builder withLookingForStuckThread(boolean enable) { - this.lookForStuckThread = enable; - return this; - } - /** * Builds a {@link FailOnTimeout} instance using the values in this builder, * wrapping the given statement. @@ -120,8 +97,7 @@ public class FailOnTimeout extends Statement { public void evaluate() throws Throwable { CallableStatement callable = new CallableStatement(); FutureTask task = new FutureTask(callable); - ThreadGroup threadGroup = threadGroupForNewThread(); - Thread thread = new Thread(threadGroup, task, "Time-limited test"); + Thread thread = new Thread(task, "Time-limited test"); thread.setDaemon(true); thread.start(); callable.awaitStarted(); @@ -131,31 +107,6 @@ public class FailOnTimeout extends Statement { } } - private ThreadGroup threadGroupForNewThread() { - if (!lookForStuckThread) { - // Use the default ThreadGroup (usually the one from the current - // thread). - return null; - } - - // Create the thread in a new ThreadGroup, so if the time-limited thread - // becomes stuck, getStuckThread() can find the thread likely to be the - // culprit. - ThreadGroup threadGroup = new ThreadGroup("FailOnTimeoutGroup"); - if (!threadGroup.isDaemon()) { - // Mark the new ThreadGroup as a daemon thread group, so it will be - // destroyed after the time-limited thread completes. By ensuring the - // ThreadGroup is destroyed, any data associated with the ThreadGroup - // (ex: via java.beans.ThreadGroupContext) is destroyed. - try { - threadGroup.setDaemon(true); - } catch (SecurityException e) { - // Swallow the exception to keep the same behavior as in JUnit 4.12. - } - } - return threadGroup; - } - /** * Wait for the test task, returning the exception thrown by the test if the * test failed, an exception indicating a timeout if the test timed out, or @@ -180,114 +131,12 @@ public class FailOnTimeout extends Statement { private Exception createTimeoutException(Thread thread) { StackTraceElement[] stackTrace = thread.getStackTrace(); - final Thread stuckThread = lookForStuckThread ? getStuckThread(thread) : null; Exception currThreadException = new TestTimedOutException(timeout, timeUnit); if (stackTrace != null) { currThreadException.setStackTrace(stackTrace); thread.interrupt(); } - if (stuckThread != null) { - Exception stuckThreadException = - new Exception("Appears to be stuck in thread " + - stuckThread.getName()); - stuckThreadException.setStackTrace(getStackTrace(stuckThread)); - return new MultipleFailureException( - Arrays.asList(currThreadException, stuckThreadException)); - } else { - return currThreadException; - } - } - - /** - * Retrieves the stack trace for a given thread. - * @param thread The thread whose stack is to be retrieved. - * @return The stack trace; returns a zero-length array if the thread has - * terminated or the stack cannot be retrieved for some other reason. - */ - private StackTraceElement[] getStackTrace(Thread thread) { - try { - return thread.getStackTrace(); - } catch (SecurityException e) { - return new StackTraceElement[0]; - } - } - - /** - * Determines whether the test appears to be stuck in some thread other than - * the "main thread" (the one created to run the test). This feature is experimental. - * Behavior may change after the 4.12 release in response to feedback. - * @param mainThread The main thread created by {@code evaluate()} - * @return The thread which appears to be causing the problem, if different from - * {@code mainThread}, or {@code null} if the main thread appears to be the - * problem or if the thread cannot be determined. The return value is never equal - * to {@code mainThread}. - */ - private Thread getStuckThread(Thread mainThread) { - List threadsInGroup = getThreadsInGroup(mainThread.getThreadGroup()); - if (threadsInGroup.isEmpty()) { - return null; - } - - // Now that we have all the threads in the test's thread group: Assume that - // any thread we're "stuck" in is RUNNABLE. Look for all RUNNABLE threads. - // If just one, we return that (unless it equals threadMain). If there's more - // than one, pick the one that's using the most CPU time, if this feature is - // supported. - Thread stuckThread = null; - long maxCpuTime = 0; - for (Thread thread : threadsInGroup) { - if (thread.getState() == Thread.State.RUNNABLE) { - long threadCpuTime = cpuTime(thread); - if (stuckThread == null || threadCpuTime > maxCpuTime) { - stuckThread = thread; - maxCpuTime = threadCpuTime; - } - } - } - return (stuckThread == mainThread) ? null : stuckThread; - } - - /** - * Returns all active threads belonging to a thread group. - * @param group The thread group. - * @return The active threads in the thread group. The result should be a - * complete list of the active threads at some point in time. Returns an empty list - * if this cannot be determined, e.g. because new threads are being created at an - * extremely fast rate. - */ - private List getThreadsInGroup(ThreadGroup group) { - final int activeThreadCount = group.activeCount(); // this is just an estimate - int threadArraySize = Math.max(activeThreadCount * 2, 100); - for (int loopCount = 0; loopCount < 5; loopCount++) { - Thread[] threads = new Thread[threadArraySize]; - int enumCount = group.enumerate(threads); - if (enumCount < threadArraySize) { - return Arrays.asList(threads).subList(0, enumCount); - } - // if there are too many threads to fit into the array, enumerate's result - // is >= the array's length; therefore we can't trust that it returned all - // the threads. Try again. - threadArraySize += 100; - } - // threads are proliferating too fast for us. Bail before we get into - // trouble. - return Collections.emptyList(); - } - - /** - * Returns the CPU time used by a thread, if possible. - * @param thr The thread to query. - * @return The CPU time used by {@code thr}, or 0 if it cannot be determined. - */ - private long cpuTime(Thread thr) { - ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); - if (mxBean.isThreadCpuTimeSupported()) { - try { - return mxBean.getThreadCpuTime(thr.getId()); - } catch (UnsupportedOperationException e) { - } - } - return 0; + return currThreadException; } private class CallableStatement implements Callable { diff --git a/src/main/java/org/junit/internal/runners/statements/RunAfters.java b/src/main/java/org/junit/internal/runners/statements/RunAfters.java index 5e56c33..7512a7d 100644 --- a/src/main/java/org/junit/internal/runners/statements/RunAfters.java +++ b/src/main/java/org/junit/internal/runners/statements/RunAfters.java @@ -30,7 +30,7 @@ public class RunAfters extends Statement { } finally { for (FrameworkMethod each : afters) { try { - invokeMethod(each); + each.invokeExplosively(target); } catch (Throwable e) { errors.add(e); } @@ -38,11 +38,4 @@ public class RunAfters extends Statement { } MultipleFailureException.assertEmpty(errors); } - - /** - * @since 4.13 - */ - protected void invokeMethod(FrameworkMethod method) throws Throwable { - method.invokeExplosively(target); - } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/statements/RunBefores.java b/src/main/java/org/junit/internal/runners/statements/RunBefores.java index bd835c7..238fbe7 100644 --- a/src/main/java/org/junit/internal/runners/statements/RunBefores.java +++ b/src/main/java/org/junit/internal/runners/statements/RunBefores.java @@ -21,15 +21,8 @@ public class RunBefores extends Statement { @Override public void evaluate() throws Throwable { for (FrameworkMethod before : befores) { - invokeMethod(before); + before.invokeExplosively(target); } next.evaluate(); } - - /** - * @since 4.13 - */ - protected void invokeMethod(FrameworkMethod method) throws Throwable { - method.invokeExplosively(target); - } } \ No newline at end of file -- cgit v1.2.3