();
+ }
+
+ @AfterClass
+ public static void afterClassCheck() {
+ stack.push("@AfterClass");
+ }
+ }
+
+ @Test
+ public void testRuleOrder() {
+ JUnitCore.runClasses(Nested.class);
+ Assert.assertEquals(
+ Arrays.toString(stack.toArray()), "[@Rule before, @Before, @After, @Rule after, @AfterClass]");
+ }
+}
diff --git lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSetupTeardownChaining.java lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSetupTeardownChaining.java
new file mode 100644
index 0000000..a099d3b
--- /dev/null
+++ lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSetupTeardownChaining.java
@@ -0,0 +1,64 @@
+package org.apache.lucene.util.junitcompat;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+/**
+ * Ensures proper functions of {@link LuceneTestCase#setUp()}
+ * and {@link LuceneTestCase#tearDown()}.
+ */
+public class TestSetupTeardownChaining extends WithNestedTests {
+ public static class NestedSetupChain extends AbstractNestedTest {
+ @Override
+ public void setUp() throws Exception {
+ // missing call.
+ }
+
+ @Test
+ public void testMe() {
+ }
+ }
+
+ public static class NestedTeardownChain extends AbstractNestedTest {
+ @Override
+ public void tearDown() throws Exception {
+ // missing call.
+ }
+
+ @Test
+ public void testMe() {
+ }
+ }
+
+ public TestSetupTeardownChaining() {
+ super(true);
+ }
+
+ /**
+ * Verify super method calls on {@link LuceneTestCase#setUp()}.
+ */
+ @Test
+ public void testSetupChaining() {
+ Result result = JUnitCore.runClasses(NestedSetupChain.class);
+ Assert.assertEquals(1, result.getFailureCount());
+ Failure failure = result.getFailures().get(0);
+ Assert.assertTrue(failure.getMessage()
+ .contains("One of the overrides of setUp does not propagate the call."));
+ }
+
+ /**
+ * Verify super method calls on {@link LuceneTestCase#tearDown()}.
+ */
+ @Test
+ public void testTeardownChaining() {
+ Result result = JUnitCore.runClasses(NestedTeardownChain.class);
+ Assert.assertEquals(1, result.getFailureCount());
+ Failure failure = result.getFailures().get(0);
+ Assert.assertTrue(failure.getMessage()
+ .contains("One of the overrides of tearDown does not propagate the call."));
+ }
+}
diff --git lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSorePointsReported.java lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSorePointsReported.java
new file mode 100644
index 0000000..c06aa18
--- /dev/null
+++ lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSorePointsReported.java
@@ -0,0 +1,266 @@
+package org.apache.lucene.util.junitcompat;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runners.model.Statement;
+
+/**
+ * Ensures proper functions of {@link LuceneTestCase#setUp()}
+ * and {@link LuceneTestCase#tearDown()}.
+ */
+public class TestSorePointsReported extends WithNestedTests {
+ public static SorePoint where;
+ public static SoreType type;
+
+ public static class Nested extends AbstractNestedTest {
+ @BeforeClass
+ public static void beforeClass() {
+ if (isRunningNested()) {
+ triggerOn(SorePoint.BEFORE_CLASS);
+ }
+ }
+
+ @Rule
+ public TestRule rule = new TestRule() {
+ @Override
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ public void evaluate() throws Throwable {
+ if (isRunningNested()) {
+ triggerOn(SorePoint.RULE);
+ }
+ base.evaluate();
+ }
+ };
+ }
+ };
+
+ /** Class initializer block/ default constructor. */
+ public Nested() {
+ triggerOn(SorePoint.INITIALIZER);
+ }
+
+ @Before
+ public void before() {
+ if (isRunningNested()) {
+ triggerOn(SorePoint.BEFORE);
+ }
+ }
+
+ @Test
+ public void test() {
+ triggerOn(SorePoint.TEST);
+ }
+
+ @After
+ public void after() {
+ if (isRunningNested()) {
+ triggerOn(SorePoint.AFTER);
+ }
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ if (isRunningNested()) {
+ triggerOn(SorePoint.AFTER_CLASS);
+ }
+ }
+
+ /** */
+ private static void triggerOn(SorePoint pt) {
+ if (pt == where) {
+ switch (type) {
+ case ASSUMPTION:
+ LuceneTestCase.assumeTrue(pt.toString(), false);
+ throw new RuntimeException("unreachable");
+ case ERROR:
+ throw new RuntimeException(pt.toString());
+ case FAILURE:
+ Assert.assertTrue(pt.toString(), false);
+ throw new RuntimeException("unreachable");
+ }
+ }
+ }
+ }
+
+ /*
+ * ASSUMPTIONS.
+ */
+
+ public TestSorePointsReported() {
+ super(true);
+ }
+
+ @Test @Ignore
+ public void testAssumeBeforeClass() throws Exception {
+ type = SoreType.ASSUMPTION;
+ where = SorePoint.BEFORE_CLASS;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: Assume failed in"));
+ }
+
+ @Test @Ignore
+ public void testAssumeInitializer() throws Exception {
+ type = SoreType.ASSUMPTION;
+ where = SorePoint.INITIALIZER;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: Assume failed in"));
+ }
+
+ @Test
+ public void testAssumeRule() throws Exception {
+ type = SoreType.ASSUMPTION;
+ where = SorePoint.RULE;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: Assume failed in"));
+ }
+
+ @Test
+ public void testAssumeBefore() throws Exception {
+ type = SoreType.ASSUMPTION;
+ where = SorePoint.BEFORE;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: Assume failed in"));
+ }
+
+ @Test
+ public void testAssumeTest() throws Exception {
+ type = SoreType.ASSUMPTION;
+ where = SorePoint.TEST;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: Assume failed in"));
+ }
+
+ @Test
+ public void testAssumeAfter() throws Exception {
+ type = SoreType.ASSUMPTION;
+ where = SorePoint.AFTER;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: Assume failed in"));
+ }
+
+ @Test @Ignore
+ public void testAssumeAfterClass() throws Exception {
+ type = SoreType.ASSUMPTION;
+ where = SorePoint.AFTER_CLASS;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: Assume failed in"));
+ }
+
+ /*
+ * FAILURES
+ */
+
+ @Test @Ignore
+ public void testFailureBeforeClass() throws Exception {
+ type = SoreType.FAILURE;
+ where = SorePoint.BEFORE_CLASS;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test @Ignore
+ public void testFailureInitializer() throws Exception {
+ type = SoreType.FAILURE;
+ where = SorePoint.INITIALIZER;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testFailureRule() throws Exception {
+ type = SoreType.FAILURE;
+ where = SorePoint.RULE;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testFailureBefore() throws Exception {
+ type = SoreType.FAILURE;
+ where = SorePoint.BEFORE;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testFailureTest() throws Exception {
+ type = SoreType.FAILURE;
+ where = SorePoint.TEST;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testFailureAfter() throws Exception {
+ type = SoreType.FAILURE;
+ where = SorePoint.AFTER;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test @Ignore
+ public void testFailureAfterClass() throws Exception {
+ type = SoreType.FAILURE;
+ where = SorePoint.AFTER_CLASS;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ /*
+ * ERRORS
+ */
+
+ @Test @Ignore
+ public void testErrorBeforeClass() throws Exception {
+ type = SoreType.ERROR;
+ where = SorePoint.BEFORE_CLASS;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test @Ignore
+ public void testErrorInitializer() throws Exception {
+ type = SoreType.ERROR;
+ where = SorePoint.INITIALIZER;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testErrorRule() throws Exception {
+ type = SoreType.ERROR;
+ where = SorePoint.RULE;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testErrorBefore() throws Exception {
+ type = SoreType.ERROR;
+ where = SorePoint.BEFORE;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testErrorTest() throws Exception {
+ type = SoreType.ERROR;
+ where = SorePoint.TEST;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test
+ public void testErrorAfter() throws Exception {
+ type = SoreType.ERROR;
+ where = SorePoint.AFTER;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ @Test @Ignore
+ public void testErrorAfterClass() throws Exception {
+ type = SoreType.ERROR;
+ where = SorePoint.AFTER_CLASS;
+ Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:"));
+ }
+
+ private String runAndReturnSyserr() throws Exception {
+ JUnitCore.runClasses(Nested.class);
+
+ String err = getSysErr();
+ // syserr.println("Type: " + type + ", point: " + where + " resulted in:\n" + err);
+ return err;
+ }
+}
diff --git lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java
new file mode 100644
index 0000000..c271b8c
--- /dev/null
+++ lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java
@@ -0,0 +1,106 @@
+package org.apache.lucene.util.junitcompat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+
+/**
+ * An abstract test class that prepares nested test classes to run.
+ * A nested test class will assume it's executed under control of this
+ * class and be ignored otherwise.
+ *
+ * The purpose of this is so that nested test suites don't run from
+ * IDEs like Eclipse (where they are automatically detected).
+ *
+ *
This class cannot extend {@link LuceneTestCase} because in case
+ * there's a nested {@link LuceneTestCase} afterclass hooks run twice and
+ * cause havoc (static fields).
+ */
+public abstract class WithNestedTests {
+ public static ThreadLocal runsAsNested = new ThreadLocal() {
+ @Override
+ protected Boolean initialValue() {
+ return false;
+ }
+ };
+
+ public static abstract class AbstractNestedTest extends LuceneTestCase {
+ @Before
+ public void before() {
+ Assume.assumeTrue(isRunningNested());
+ }
+
+ protected static boolean isRunningNested() {
+ return runsAsNested.get() != null && runsAsNested.get();
+ }
+ }
+
+ private boolean suppressOutputStreams;
+
+ protected WithNestedTests(boolean suppressOutputStreams) {
+ this.suppressOutputStreams = suppressOutputStreams;
+ }
+
+ protected PrintStream prevSysErr;
+ protected PrintStream prevSysOut;
+ protected ByteArrayOutputStream sysout;
+ protected ByteArrayOutputStream syserr;
+
+ @Before
+ public final void before() {
+ if (suppressOutputStreams) {
+ prevSysOut = System.out;
+ prevSysErr = System.err;
+
+ try {
+ sysout = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(sysout, true, "UTF-8"));
+ syserr = new ByteArrayOutputStream();
+ System.setErr(new PrintStream(syserr, true, "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ runsAsNested.set(true);
+ }
+
+ @After
+ public final void after() {
+ runsAsNested.set(false);
+
+ if (suppressOutputStreams) {
+ System.out.flush();
+ System.err.flush();
+
+ System.setOut(prevSysOut);
+ System.setErr(prevSysErr);
+ }
+ }
+
+ protected String getSysOut() {
+ Assert.assertTrue(suppressOutputStreams);
+ System.out.flush();
+ try {
+ return new String(sysout.toByteArray(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected String getSysErr() {
+ Assert.assertTrue(suppressOutputStreams);
+ System.err.flush();
+ try {
+ return new String(syserr.toByteArray(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git lucene/lib/junit-4.10.jar lucene/lib/junit-4.10.jar
new file mode 100644
index 0000000..954851e
Binary files /dev/null and lucene/lib/junit-4.10.jar differ
diff --git lucene/lib/junit-4.7.jar lucene/lib/junit-4.7.jar
deleted file mode 100755
index 700ad69..0000000
Binary files lucene/lib/junit-4.7.jar and /dev/null differ
diff --git lucene/lib/junit-NOTICE.txt lucene/lib/junit-NOTICE.txt
index ee48d04..f9796ea 100644
--- lucene/lib/junit-NOTICE.txt
+++ lucene/lib/junit-NOTICE.txt
@@ -1,2 +1,2 @@
-JUnit (under lib/junit-4.7.jar) is licensed under the Common Public License v. 1.0
+JUnit (under lib/junit-4.10.jar) is licensed under the Common Public License v. 1.0
See http://junit.sourceforge.net/cpl-v10.html
\ No newline at end of file
diff --git lucene/test-framework/src/java/org/apache/lucene/util/InternalAssumptionViolatedException.java lucene/test-framework/src/java/org/apache/lucene/util/InternalAssumptionViolatedException.java
new file mode 100644
index 0000000..2bece4b
--- /dev/null
+++ lucene/test-framework/src/java/org/apache/lucene/util/InternalAssumptionViolatedException.java
@@ -0,0 +1,57 @@
+package org.apache.lucene.util;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import org.hamcrest.Description;
+import org.junit.internal.AssumptionViolatedException;
+
+/**
+ * We have our own "custom" assumption class because JUnit's {@link AssumptionViolatedException}
+ * does not allow a cause exception to be set.
+ *
+ * We currently subclass and substitute JUnit's internal AVE.
+ */
+@SuppressWarnings("serial")
+final class InternalAssumptionViolatedException extends AssumptionViolatedException {
+ private final String message;
+
+ public InternalAssumptionViolatedException(String message) {
+ this(message, null);
+ }
+
+ public InternalAssumptionViolatedException(String message, Throwable t) {
+ super(t, /* no matcher. */ null);
+ if (getCause() != t) {
+ throw new Error("AssumptionViolationException not setting up getCause() properly? Panic.");
+ }
+ this.message = message;
+ }
+
+ @Override
+ public String getMessage() {
+ return super.getMessage();
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("failed assumption: " + message);
+ if (getCause() != null) {
+ description.appendText("(throwable: " + getCause().toString() + ")");
+ }
+ }
+}
\ No newline at end of file
diff --git lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
index cd8458b..3960d9a 100644
--- lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
+++ lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
@@ -24,22 +24,43 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.Field.TermVector;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.index.*;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.LogByteSizeMergePolicy;
+import org.apache.lucene.index.LogDocMergePolicy;
+import org.apache.lucene.index.LogMergePolicy;
+import org.apache.lucene.index.MergePolicy;
+import org.apache.lucene.index.MockRandomMergePolicy;
+import org.apache.lucene.index.SerialMergeScheduler;
+import org.apache.lucene.index.SlowMultiReaderWrapper;
+import org.apache.lucene.index.TieredMergePolicy;
import org.apache.lucene.search.AssertingIndexSearcher;
import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.FieldCache.CacheEntry;
import org.apache.lucene.search.FieldCache;
+import org.apache.lucene.search.FieldCache.CacheEntry;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
@@ -55,10 +76,13 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
-import org.junit.rules.MethodRule;
-import org.junit.rules.TestWatchman;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
import org.junit.runner.RunWith;
-import org.junit.runners.model.FrameworkMethod;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunListener;
import org.junit.runners.model.Statement;
/**
@@ -90,7 +114,6 @@ import org.junit.runners.model.Statement;
@RunWith(LuceneTestCaseRunner.class)
public abstract class LuceneTestCase extends Assert {
-
/**
* true iff tests are run in verbose mode. Note: if it is false, tests are not
* expected to print any messages.
@@ -153,17 +176,16 @@ public abstract class LuceneTestCase extends Assert {
private int savedBoolMaxClauseCount = BooleanQuery.getMaxClauseCount();
private volatile Thread.UncaughtExceptionHandler savedUncaughtExceptionHandler = null;
-
- /** Used to track if setUp and tearDown are called correctly from subclasses */
- private static State state = State.INITIAL;
+ /**
+ * @see SubclassSetupTeardownRule
+ */
+ private boolean setupCalled;
+
+ /**
+ * @see SubclassSetupTeardownRule
+ */
+ private boolean teardownCalled;
- private static enum State {
- INITIAL, // no tests ran yet
- SETUP, // test has called setUp()
- RANTEST, // test is running
- TEARDOWN // test has called tearDown()
- }
-
private static class UncaughtExceptionEntry {
public final Thread thread;
public final Throwable exception;
@@ -199,7 +221,6 @@ public abstract class LuceneTestCase extends Assert {
@BeforeClass
public static void beforeClassLuceneTestCaseJ4() {
initRandom();
- state = State.INITIAL;
tempDirs.clear();
stores = Collections.synchronizedMap(new IdentityHashMap());
// enable this by default, for IDE consistency with ant tests (as its the default from ant)
@@ -246,18 +267,7 @@ public abstract class LuceneTestCase extends Assert {
@AfterClass
public static void afterClassLuceneTestCaseJ4() {
- State oldState = state; // capture test execution state
- state = State.INITIAL; // set the state for subsequent tests
-
Throwable problem = null;
- try {
- if (!testsFailed) {
- assertTrue("ensure your setUp() calls super.setUp() and your tearDown() calls super.tearDown()!!!",
- oldState == State.INITIAL || oldState == State.TEARDOWN);
- }
- } catch (Throwable t) {
- if (problem == null) problem = t;
- }
if (! "false".equals(TEST_CLEAN_THREADS)) {
int rogueThreads = threadCleanup("test class");
@@ -373,78 +383,129 @@ public abstract class LuceneTestCase extends Assert {
}
protected static boolean testsFailed; /* true if any tests failed */
-
- // This is how we get control when errors occur.
- // Think of this as start/end/success/failed
- // events.
- @Rule
- public final TestWatchman intercept = new TestWatchman() {
+ /**
+ * Control the outcome of each test's output status (failure, assumption-failure). This
+ * would ideally be handled by attaching a {@link RunListener} to a {@link Runner} (because
+ * then we would be notified about static block failures).
+ */
+ private class TestResultInterceptorRule implements TestRule {
@Override
- public void failed(Throwable e, FrameworkMethod method) {
- // org.junit.internal.AssumptionViolatedException in older releases
- // org.junit.Assume.AssumptionViolatedException in recent ones
- if (e.getClass().getName().endsWith("AssumptionViolatedException")) {
- if (e.getCause() instanceof _TestIgnoredException)
- e = e.getCause();
- System.err.print("NOTE: Assume failed in '" + method.getName() + "' (ignored):");
- if (VERBOSE) {
- System.err.println();
- e.printStackTrace(System.err);
- } else {
- System.err.print(" ");
- System.err.println(e.getMessage());
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ starting(description);
+ try {
+ base.evaluate();
+ } catch (AssumptionViolatedException e) {
+ assumptionIgnored(e, description);
+ throw e;
+ } catch (Throwable t) {
+ failed(t, description);
+ throw t;
+ } finally {
+ ending(description);
+ }
}
+ };
+ }
+
+ private void assumptionIgnored(AssumptionViolatedException e, Description description) {
+ System.err.print("NOTE: Assume failed in '" + description.getDisplayName() + "' (ignored):");
+ if (VERBOSE) {
+ System.err.println();
+ e.printStackTrace(System.err);
} else {
- testsFailed = true;
- reportAdditionalFailureInfo();
+ System.err.print(" ");
+ System.err.println(e.getMessage());
}
- super.failed(e, method);
}
- @Override
- public void starting(FrameworkMethod method) {
+ private void failed(Throwable e, Description description) {
+ testsFailed = true;
+ reportAdditionalFailureInfo();
+ assert !(e instanceof AssumptionViolatedException);
+ }
+
+ private void starting(Description description) {
// set current method name for logging
- LuceneTestCase.this.name = method.getName();
- State s = state; // capture test execution state
- state = State.RANTEST; // set the state for subsequent tests
- if (!testsFailed) {
- assertTrue("ensure your setUp() calls super.setUp()!!!", s == State.SETUP);
- }
- super.starting(method);
+ LuceneTestCase.this.name = description.getDisplayName();
+ }
+
+ private void ending(Description description) {
+ // clear the current method name.
+ LuceneTestCase.this.name = null;
}
};
-
+
/**
* The thread executing the current test case.
* @see #isTestThread()
*/
volatile Thread testCaseThread;
- /** @see #testCaseThread */
- @Rule
- public final MethodRule setTestThread = new MethodRule() {
- public Statement apply(final Statement s, FrameworkMethod fm, Object target) {
+ /**
+ * @see LuceneTestCase#testCaseThread
+ */
+ private class RememberThreadRule implements TestRule {
+ @Override
+ public Statement apply(final Statement base, Description description) {
return new Statement() {
public void evaluate() throws Throwable {
try {
LuceneTestCase.this.testCaseThread = Thread.currentThread();
- s.evaluate();
+ base.evaluate();
} finally {
LuceneTestCase.this.testCaseThread = null;
}
}
};
}
- };
+ }
- @Before
- public void setUp() throws Exception {
+ /**
+ * This controls how rules are nested. It is important that _all_ rules declared
+ * in {@link LuceneTestCase} are executed in proper order if they depend on each
+ * other.
+ */
+ @Rule
+ public final TestRule ruleChain = RuleChain
+ .outerRule(new RememberThreadRule())
+ .around(new TestResultInterceptorRule())
+ .around(new InternalSetupTeardownRule())
+ .around(new SubclassSetupTeardownRule());
+
+ /**
+ * Internal {@link LuceneTestCase} setup before/after each test.
+ */
+ private class InternalSetupTeardownRule implements TestRule {
+ @Override
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ setUpInternal();
+ // We simulate the previous behavior of @Before in that
+ // if any statement below us fails, we just propagate the original
+ // exception and do not call tearDownInternal.
+
+ // TODO: [DW] should this really be this way? We could use
+ // JUnit's MultipleFailureException and propagate both?
+ base.evaluate();
+ tearDownInternal();
+ }
+ };
+ }
+ }
+
+ /**
+ * Setup before the tests.
+ */
+ private final void setUpInternal() throws Exception {
seed = "random".equals(TEST_SEED) ? seedRand.nextLong() : ThreeLongs.fromString(TEST_SEED).l2;
random.setSeed(seed);
- State s = state; // capture test execution state
- state = State.SETUP; // set the state for subsequent tests
-
+
savedUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
@@ -458,8 +519,6 @@ public abstract class LuceneTestCase extends Assert {
break;
}
}
- if (e.getCause() instanceof _TestIgnoredException)
- e = e.getCause();
System.err.print("NOTE: Assume failed at " + where + " (ignored):");
if (VERBOSE) {
System.err.println();
@@ -478,10 +537,6 @@ public abstract class LuceneTestCase extends Assert {
});
savedBoolMaxClauseCount = BooleanQuery.getMaxClauseCount();
-
- if (!testsFailed) {
- assertTrue("ensure your tearDown() calls super.tearDown()!!!", (s == State.INITIAL || s == State.TEARDOWN));
- }
}
/**
@@ -533,26 +588,57 @@ public abstract class LuceneTestCase extends Assert {
return Thread.currentThread() == testCaseThread;
}
+ /**
+ * Make sure {@link #setUp()} and {@link #tearDown()} were invoked even if they
+ * have been overriden. We assume nobody will call these out of non-overriden
+ * methods (they have to be public by contract, unfortunately). The top-level
+ * methods just set a flag that is checked upon successful execution of each test
+ * case.
+ */
+ private class SubclassSetupTeardownRule implements TestRule {
+ @Override
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ setupCalled = false;
+ teardownCalled = false;
+ base.evaluate();
+
+ // I assume we don't want to check teardown chaining if something happens in the
+ // test because this would obscure the original exception?
+ if (!setupCalled) {
+ Assert.fail("One of the overrides of setUp does not propagate the call.");
+ }
+ if (!teardownCalled) {
+ Assert.fail("One of the overrides of tearDown does not propagate the call.");
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * For subclassing only. Overrides must call {@code super.setUp()}.
+ */
+ @Before
+ public void setUp() throws Exception {
+ setupCalled = true;
+ }
+
+ /**
+ * For subclassing only. Overrides must call {@code super.tearDown()}.
+ */
@After
public void tearDown() throws Exception {
- State oldState = state; // capture test execution state
- state = State.TEARDOWN; // set the state for subsequent tests
-
- // NOTE: with junit 4.7, we don't get a reproduceWith because our Watchman
- // does not know if something fails in tearDown. so we ensure this happens ourselves for now.
- // we can remove this if we upgrade to 4.8
- Throwable problem = null;
-
- try {
- if (!testsFailed) {
- // Note: we allow a test to go straight from SETUP -> TEARDOWN (without ever entering the RANTEST state)
- // because if you assume() inside setUp(), it skips the test and the TestWatchman has no way to know...
- assertTrue("ensure your setUp() calls super.setUp()!!!", oldState == State.RANTEST || oldState == State.SETUP);
- }
- } catch (Throwable t) {
- if (problem == null) problem = t;
- }
+ teardownCalled = true;
+ }
+ /**
+ * Clean up after tests.
+ */
+ private final void tearDownInternal() throws Exception {
+ Throwable problem = null;
BooleanQuery.setMaxClauseCount(savedBoolMaxClauseCount);
// this won't throw any exceptions or fail the test
@@ -588,8 +674,8 @@ public abstract class LuceneTestCase extends Assert {
purgeFieldCache(FieldCache.DEFAULT);
if (problem != null) {
- testsFailed = true;
reportAdditionalFailureInfo();
+ // TODO: simply rethrow problem, without wrapping?
throw new RuntimeException(problem);
}
}
@@ -795,7 +881,7 @@ public abstract class LuceneTestCase extends Assert {
}
public static void assumeTrue(String msg, boolean b) {
- Assume.assumeNoException(b ? null : new _TestIgnoredException(msg));
+ Assume.assumeNoException(b ? null : new InternalAssumptionViolatedException(msg));
}
public static void assumeFalse(String msg, boolean b) {
@@ -803,7 +889,7 @@ public abstract class LuceneTestCase extends Assert {
}
public static void assumeNoException(String msg, Exception e) {
- Assume.assumeNoException(e == null ? null : new _TestIgnoredException(msg, e));
+ Assume.assumeNoException(e == null ? null : new InternalAssumptionViolatedException(msg, e));
}
public static Set asSet(T... args) {
@@ -1337,5 +1423,4 @@ public abstract class LuceneTestCase extends Assert {
return true;
}
}
-
}
diff --git lucene/test-framework/src/java/org/apache/lucene/util/_TestIgnoredException.java lucene/test-framework/src/java/org/apache/lucene/util/_TestIgnoredException.java
deleted file mode 100644
index 3664cb0..0000000
--- lucene/test-framework/src/java/org/apache/lucene/util/_TestIgnoredException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.lucene.util;
-
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-import java.io.PrintStream;
-
-/** Replacement for Assume jUnit class, so we can add a message with explanation */
-final class _TestIgnoredException extends RuntimeException {
-
- _TestIgnoredException(String msg) {
- super(msg);
- }
-
- _TestIgnoredException(String msg, Throwable t) {
- super(msg, t);
- }
-
- @Override
- public String getMessage() {
- StringBuilder sb = new StringBuilder(super.getMessage());
- if (getCause() != null)
- sb.append(" - ").append(getCause());
- return sb.toString();
- }
-
- // only this one is called by our code, exception is not used outside this class:
- @Override
- public void printStackTrace(PrintStream s) {
- if (getCause() != null) {
- s.println(super.toString() + " - Caused by:");
- getCause().printStackTrace(s);
- } else {
- super.printStackTrace(s);
- }
- }
-}
diff --git solr/NOTICE.txt solr/NOTICE.txt
index 56c7c06..a5abe2f 100644
--- solr/NOTICE.txt
+++ solr/NOTICE.txt
@@ -66,7 +66,7 @@ the Apache CXF project and is Apache License 2.0.
The Google Code Prettify is Apache License 2.0.
See http://code.google.com/p/google-code-prettify/
-JUnit (under lib/junit-4.7.jar) is licensed under the Common Public License v. 1.0
+JUnit (under lib/junit-4.10.jar) is licensed under the Common Public License v. 1.0
See http://junit.sourceforge.net/cpl-v10.html
JLine (under contrib/lucli/lib/jline.jar) is licensed under the BSD License.
diff --git solr/lib/junit-4.10.jar solr/lib/junit-4.10.jar
new file mode 100644
index 0000000..954851e
Binary files /dev/null and solr/lib/junit-4.10.jar differ
diff --git solr/lib/junit-4.7.jar solr/lib/junit-4.7.jar
deleted file mode 100755
index 700ad69..0000000
Binary files solr/lib/junit-4.7.jar and /dev/null differ