diff --git dev-tools/eclipse/dot.classpath dev-tools/eclipse/dot.classpath index b23a864..49891b0 100644 --- dev-tools/eclipse/dot.classpath +++ dev-tools/eclipse/dot.classpath @@ -89,7 +89,7 @@ - + @@ -109,7 +109,7 @@ - + diff --git dev-tools/idea/.idea/libraries/JUnit.xml dev-tools/idea/.idea/libraries/JUnit.xml index 4710fc8..f4f4221 100644 --- dev-tools/idea/.idea/libraries/JUnit.xml +++ dev-tools/idea/.idea/libraries/JUnit.xml @@ -1,7 +1,7 @@ - + diff --git dev-tools/maven/pom.xml.template dev-tools/maven/pom.xml.template index 7b94e47..fbf1a34 100644 --- dev-tools/maven/pom.xml.template +++ dev-tools/maven/pom.xml.template @@ -197,7 +197,7 @@ junit junit - 4.7 + 4.10 org.apache.ant diff --git lucene/NOTICE.txt lucene/NOTICE.txt index de9e11a..c12bc53 100644 --- lucene/NOTICE.txt +++ lucene/NOTICE.txt @@ -86,7 +86,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 lucene/README.txt lucene/README.txt index 7bc336b..6f39537 100644 --- lucene/README.txt +++ lucene/README.txt @@ -22,7 +22,7 @@ lucene-core-XX-javadoc.jar lucene-test-framework-XX.jar The compiled Lucene test-framework library. - Depends on junit 4.7.x (not 4.6.x, not 4.8.x), and Apache Ant 1.7.x (not 1.6.x, not 1.8.x) + Depends on junit 4.10, and Apache Ant 1.7.x (not 1.6.x, not 1.8.x) lucene-test-framework-XX-javadoc.jar The Javadoc jar for the compiled Lucene test-framework library. diff --git lucene/backwards/src/test-framework/java/org/apache/lucene/util/LuceneTestCase.java lucene/backwards/src/test-framework/java/org/apache/lucene/util/LuceneTestCase.java index 3a0fb02..294ce8b 100644 --- lucene/backwards/src/test-framework/java/org/apache/lucene/util/LuceneTestCase.java +++ lucene/backwards/src/test-framework/java/org/apache/lucene/util/LuceneTestCase.java @@ -154,16 +154,6 @@ public abstract class LuceneTestCase extends Assert { private volatile Thread.UncaughtExceptionHandler savedUncaughtExceptionHandler = null; - /** Used to track if setUp and tearDown are called correctly from subclasses */ - private static State state = State.INITIAL; - - 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 +189,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,19 +235,8 @@ 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"); if (rogueThreads > 0) { @@ -406,11 +384,6 @@ public abstract class LuceneTestCase extends Assert { public void starting(FrameworkMethod method) { // 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); } }; @@ -442,9 +415,6 @@ public abstract class LuceneTestCase extends Assert { public void setUp() 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) { @@ -456,10 +426,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)); - } } /** @@ -513,24 +479,11 @@ public abstract class LuceneTestCase extends Assert { @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; - } - BooleanQuery.setMaxClauseCount(savedBoolMaxClauseCount); // this won't throw any exceptions or fail the test diff --git lucene/common-build.xml lucene/common-build.xml index e178766..aa051fb 100644 --- lucene/common-build.xml +++ lucene/common-build.xml @@ -52,7 +52,7 @@ - + diff --git lucene/contrib/misc/src/java/org/apache/lucene/store/NativePosixUtil.cpp lucene/contrib/misc/src/java/org/apache/lucene/store/NativePosixUtil.cpp index fa05142..f128f3b 100644 --- lucene/contrib/misc/src/java/org/apache/lucene/store/NativePosixUtil.cpp +++ lucene/contrib/misc/src/java/org/apache/lucene/store/NativePosixUtil.cpp @@ -24,7 +24,7 @@ #include // constants for open #include // constants for open -// java -cp .:lib/junit-4.7.jar:./build/classes/test:./build/classes/java:./build/classes/demo -Dlucene.version=2.9-dev -DtempDir=build -ea org.junit.runner.JUnitCore org.apache.lucene.index.TestDoc +// java -cp .:lib/junit-4.10.jar:./build/classes/test:./build/classes/java:./build/classes/demo -Dlucene.version=2.9-dev -DtempDir=build -ea org.junit.runner.JUnitCore org.apache.lucene.index.TestDoc /* * Class: org_apache_lucene_store_NativePosixUtil diff --git lucene/core/src/test/org/apache/lucene/index/Test2BTerms.java lucene/core/src/test/org/apache/lucene/index/Test2BTerms.java index a055b5e..bd63788 100644 --- lucene/core/src/test/org/apache/lucene/index/Test2BTerms.java +++ lucene/core/src/test/org/apache/lucene/index/Test2BTerms.java @@ -36,7 +36,7 @@ import org.junit.Ignore; // // ant compile-test // -// java -server -Xmx8g -d64 -cp .:lib/junit-4.7.jar:./build/classes/test:./build/classes/test-framework:./build/classes/java -Dlucene.version=4.0-dev -Dtests.directory=MMapDirectory -DtempDir=build -ea org.junit.runner.JUnitCore org.apache.lucene.index.Test2BTerms +// java -server -Xmx8g -d64 -cp .:lib/junit-4.10.jar:./build/classes/test:./build/classes/test-framework:./build/classes/java -Dlucene.version=4.0-dev -Dtests.directory=MMapDirectory -DtempDir=build -ea org.junit.runner.JUnitCore org.apache.lucene.index.Test2BTerms // public class Test2BTerms extends LuceneTestCase { diff --git lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java index 426428f..8aaf30b 100644 --- lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java +++ lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java @@ -1392,7 +1392,7 @@ public class TestFSTs extends LuceneTestCase { } } - // java -cp build/classes/test:build/classes/test-framework:build/classes/java:lib/junit-4.7.jar org.apache.lucene.util.fst.TestFSTs /x/tmp/allTerms3.txt out + // java -cp build/classes/test:build/classes/test-framework:build/classes/java:lib/junit-4.10.jar org.apache.lucene.util.fst.TestFSTs /x/tmp/allTerms3.txt out public static void main(String[] args) throws IOException { int prune = 0; int limit = Integer.MAX_VALUE; diff --git lucene/core/src/test/org/apache/lucene/util/junitcompat/SorePoint.java lucene/core/src/test/org/apache/lucene/util/junitcompat/SorePoint.java new file mode 100644 index 0000000..b0bfebd --- /dev/null +++ lucene/core/src/test/org/apache/lucene/util/junitcompat/SorePoint.java @@ -0,0 +1,16 @@ +package org.apache.lucene.util.junitcompat; + +/** + * A pointcut-like definition where we should trigger + * an assumption or error. + */ +public enum SorePoint { + // STATIC_INITIALIZER, // I assume this will result in JUnit failure to load a suite. + BEFORE_CLASS, + INITIALIZER, + RULE, + BEFORE, + TEST, + AFTER, + AFTER_CLASS +} \ No newline at end of file diff --git lucene/core/src/test/org/apache/lucene/util/junitcompat/SoreType.java lucene/core/src/test/org/apache/lucene/util/junitcompat/SoreType.java new file mode 100644 index 0000000..e93940b --- /dev/null +++ lucene/core/src/test/org/apache/lucene/util/junitcompat/SoreType.java @@ -0,0 +1,7 @@ +package org.apache.lucene.util.junitcompat; + +public enum SoreType { + ASSUMPTION, + FAILURE, + ERROR +} diff --git lucene/core/src/test/org/apache/lucene/util/junitcompat/TestJUnitRuleOrder.java lucene/core/src/test/org/apache/lucene/util/junitcompat/TestJUnitRuleOrder.java new file mode 100644 index 0000000..9e5f7d3 --- /dev/null +++ lucene/core/src/test/org/apache/lucene/util/junitcompat/TestJUnitRuleOrder.java @@ -0,0 +1,75 @@ +package org.apache.lucene.util.junitcompat; + +import java.util.Arrays; +import java.util.Stack; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +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; + +/** + * This verifies that JUnit {@link Rule}s are invoked before + * {@link Before} and {@link After} hooks. This should be the + * case from JUnit 4.10 on. + */ +public class TestJUnitRuleOrder extends WithNestedTests { + static Stack stack; + + public TestJUnitRuleOrder() { + super(true); + } + + public static class Nested extends WithNestedTests.AbstractNestedTest { + @Before + public void before() { + stack.push("@Before"); + } + + @After + public void after() { + stack.push("@After"); + } + + @Rule + public TestRule testRule = new TestRule() { + @Override + public Statement apply(final Statement base, Description description) { + return new Statement() { + public void evaluate() throws Throwable { + stack.push("@Rule before"); + base.evaluate(); + stack.push("@Rule after"); + } + }; + } + }; + + @Test + public void test() {/* empty */} + + @BeforeClass + public static void beforeClassCleanup() { + stack = new Stack(); + } + + @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