From 917a88fad06ce108a596a8fdb4607b1a2fbb3f3e Mon Sep 17 00:00:00 2001 From: Matthew Farwell Date: Tue, 3 Jan 2012 22:49:19 +0100 Subject: [PATCH] Added MainRunner. This removes the need for public methods in JUnitCore MainRunner installs a SecurityManager which traps the System.exit(), thereby removing the need to have runMainAndExit and runMain public in JUnitCore. MainRunner is only used in the tests of course. --- .../java/org/junit/internal/JUnitSystem.java | 1 - .../java/org/junit/internal/RealSystem.java | 5 -- src/main/java/org/junit/runner/JUnitCore.java | 13 ++-- src/test/java/org/junit/tests/TestSystem.java | 5 -- .../tests/running/core/CommandLineTest.java | 9 ++- .../JUnitCoreReturnsCorrectExitCodeTest.java | 12 ++-- .../junit/tests/running/core/MainRunner.java | 69 +++++++++++++++++++ 7 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 src/test/java/org/junit/tests/running/core/MainRunner.java diff --git a/src/main/java/org/junit/internal/JUnitSystem.java b/src/main/java/org/junit/internal/JUnitSystem.java index 6d9c242e643c..7c4497af6bbb 100644 --- a/src/main/java/org/junit/internal/JUnitSystem.java +++ b/src/main/java/org/junit/internal/JUnitSystem.java @@ -3,6 +3,5 @@ import java.io.PrintStream; public interface JUnitSystem { - void exit(int i); PrintStream out(); } diff --git a/src/main/java/org/junit/internal/RealSystem.java b/src/main/java/org/junit/internal/RealSystem.java index 1067c6d36b5c..5ed1e141b1fc 100644 --- a/src/main/java/org/junit/internal/RealSystem.java +++ b/src/main/java/org/junit/internal/RealSystem.java @@ -3,11 +3,6 @@ import java.io.PrintStream; public class RealSystem implements JUnitSystem { - - public void exit(int code) { - System.exit(code); - } - public PrintStream out() { return System.out; } diff --git a/src/main/java/org/junit/runner/JUnitCore.java b/src/main/java/org/junit/runner/JUnitCore.java index f24e6d62d245..ba3dd154abc5 100644 --- a/src/main/java/org/junit/runner/JUnitCore.java +++ b/src/main/java/org/junit/runner/JUnitCore.java @@ -39,12 +39,13 @@ public static void main(String... args) { } /** - * Do not use. Testing purposes only. - * @param system + * Runs main and exits + * @param system + * @args args from main() */ - public static void runMainAndExit(JUnitSystem system, String... args) { + private static void runMainAndExit(JUnitSystem system, String... args) { Result result= new JUnitCore().runMain(system, args); - system.exit(result.wasSuccessful() ? 0 : 1); + System.exit(result.wasSuccessful() ? 0 : 1); } /** @@ -70,10 +71,10 @@ public static Result runClasses(Class... classes) { } /** - * Do not use. Testing purposes only. * @param system + * @args args from main() */ - public Result runMain(JUnitSystem system, String... args) { + private Result runMain(JUnitSystem system, String... args) { system.out().println("JUnit version " + Version.id()); List> classes= new ArrayList>(); List missingClasses= new ArrayList(); diff --git a/src/test/java/org/junit/tests/TestSystem.java b/src/test/java/org/junit/tests/TestSystem.java index 9271d3b88884..43448090f9be 100644 --- a/src/test/java/org/junit/tests/TestSystem.java +++ b/src/test/java/org/junit/tests/TestSystem.java @@ -8,7 +8,6 @@ public class TestSystem implements JUnitSystem { private PrintStream out; - public int fCode; private ByteArrayOutputStream fOutContents; public TestSystem() { @@ -16,10 +15,6 @@ public TestSystem() { out= new PrintStream(fOutContents); } - public void exit(int code) { - fCode= code; - } - public PrintStream out() { return out; } diff --git a/src/test/java/org/junit/tests/running/core/CommandLineTest.java b/src/test/java/org/junit/tests/running/core/CommandLineTest.java index cdf8b5547db5..971ce1cd05b7 100644 --- a/src/test/java/org/junit/tests/running/core/CommandLineTest.java +++ b/src/test/java/org/junit/tests/running/core/CommandLineTest.java @@ -9,7 +9,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.internal.RealSystem; import org.junit.runner.JUnitCore; public class CommandLineTest { @@ -34,8 +33,12 @@ static public class Example { } @Test public void runATest() { - testWasRun= false; // todo create a TestSystem instead - new JUnitCore().runMain(new RealSystem(), new String[]{"org.junit.tests.running.core.CommandLineTest$Example"}); + testWasRun= false; + new MainRunner().runWithCheckForSystemExit(new Runnable() { + public void run() { + JUnitCore.main("org.junit.tests.running.core.CommandLineTest$Example"); + } + }); assertTrue(testWasRun); } diff --git a/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java b/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java index 0d8bb370ffdf..b16281310ee8 100644 --- a/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java +++ b/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java @@ -4,7 +4,6 @@ import static org.junit.Assert.fail; import org.junit.Test; import org.junit.runner.JUnitCore; -import org.junit.tests.TestSystem; public class JUnitCoreReturnsCorrectExitCodeTest { @@ -31,9 +30,12 @@ static public class Succeed { runClass(getClass().getName() + "$Succeed", 0); } - private void runClass(String className, int returnCode) { - TestSystem system= new TestSystem(); - JUnitCore.runMainAndExit(system, className); - assertEquals(returnCode, system.fCode); + private void runClass(final String className, int returnCode) { + Integer exitValue= new MainRunner().runWithCheckForSystemExit(new Runnable() { + public void run() { + JUnitCore.main(className); + } + }); + assertEquals(Integer.valueOf(returnCode), exitValue); } } diff --git a/src/test/java/org/junit/tests/running/core/MainRunner.java b/src/test/java/org/junit/tests/running/core/MainRunner.java new file mode 100644 index 000000000000..75ed9405d52f --- /dev/null +++ b/src/test/java/org/junit/tests/running/core/MainRunner.java @@ -0,0 +1,69 @@ +package org.junit.tests.running.core; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.security.Permission; + +public class MainRunner { + + private static class ExitException extends SecurityException { + private static final long serialVersionUID= -9104651568237766642L; + + private final int status; + + public ExitException(int status) { + super(""); + this.status= status; + } + + public int getStatus() { + return status; + } + } + + private static class NoExitSecurityManager extends SecurityManager { + @Override + public void checkPermission(Permission perm) { + // allow anything. + } + + @Override + public void checkPermission(Permission perm, Object context) { + // allow anything. + } + + @Override + public void checkExit(int status) { + super.checkExit(status); + throw new ExitException(status); + } + } + + /** + * Execute runnable.run(), preventing System.exit(). If System.exit() is called + * in runnable.run(), the value is returned. If System.exit() + * is not called, null is returned. + * + * @param runnable + * @return null if System.exit() is not called, Integer.valueof(status) if not + */ + public Integer runWithCheckForSystemExit(Runnable runnable) { + SecurityManager oldSecurityManager = System.getSecurityManager(); + System.setSecurityManager(new NoExitSecurityManager()); + PrintStream oldPrintStream = System.out; + + System.setOut(new PrintStream(new ByteArrayOutputStream())); + try { + runnable.run(); + System.out.println("System.exit() not called, return null"); + return null; + } catch (ExitException e) { + System.out.println("System.exit() called, value=" + e.getStatus()); + return e.getStatus(); + } finally { + System.setSecurityManager(oldSecurityManager); + System.setOut(oldPrintStream); + } + } + +}