Skip to content

Commit 917a88f

Browse files
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.
1 parent 45eaab7 commit 917a88f

File tree

7 files changed

+89
-25
lines changed

7 files changed

+89
-25
lines changed

src/main/java/org/junit/internal/JUnitSystem.java

-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@
33
import java.io.PrintStream;
44

55
public interface JUnitSystem {
6-
void exit(int i);
76
PrintStream out();
87
}

src/main/java/org/junit/internal/RealSystem.java

-5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@
33
import java.io.PrintStream;
44

55
public class RealSystem implements JUnitSystem {
6-
7-
public void exit(int code) {
8-
System.exit(code);
9-
}
10-
116
public PrintStream out() {
127
return System.out;
138
}

src/main/java/org/junit/runner/JUnitCore.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ public static void main(String... args) {
3939
}
4040

4141
/**
42-
* Do not use. Testing purposes only.
43-
* @param system
42+
* Runs main and exits
43+
* @param system
44+
* @args args from main()
4445
*/
45-
public static void runMainAndExit(JUnitSystem system, String... args) {
46+
private static void runMainAndExit(JUnitSystem system, String... args) {
4647
Result result= new JUnitCore().runMain(system, args);
47-
system.exit(result.wasSuccessful() ? 0 : 1);
48+
System.exit(result.wasSuccessful() ? 0 : 1);
4849
}
4950

5051
/**
@@ -70,10 +71,10 @@ public static Result runClasses(Class<?>... classes) {
7071
}
7172

7273
/**
73-
* Do not use. Testing purposes only.
7474
* @param system
75+
* @args args from main()
7576
*/
76-
public Result runMain(JUnitSystem system, String... args) {
77+
private Result runMain(JUnitSystem system, String... args) {
7778
system.out().println("JUnit version " + Version.id());
7879
List<Class<?>> classes= new ArrayList<Class<?>>();
7980
List<Failure> missingClasses= new ArrayList<Failure>();

src/test/java/org/junit/tests/TestSystem.java

-5
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,13 @@
88

99
public class TestSystem implements JUnitSystem {
1010
private PrintStream out;
11-
public int fCode;
1211
private ByteArrayOutputStream fOutContents;
1312

1413
public TestSystem() {
1514
fOutContents= new ByteArrayOutputStream();
1615
out= new PrintStream(fOutContents);
1716
}
1817

19-
public void exit(int code) {
20-
fCode= code;
21-
}
22-
2318
public PrintStream out() {
2419
return out;
2520
}

src/test/java/org/junit/tests/running/core/CommandLineTest.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import org.junit.After;
1010
import org.junit.Before;
1111
import org.junit.Test;
12-
import org.junit.internal.RealSystem;
1312
import org.junit.runner.JUnitCore;
1413

1514
public class CommandLineTest {
@@ -34,8 +33,12 @@ static public class Example {
3433
}
3534

3635
@Test public void runATest() {
37-
testWasRun= false; // todo create a TestSystem instead
38-
new JUnitCore().runMain(new RealSystem(), new String[]{"org.junit.tests.running.core.CommandLineTest$Example"});
36+
testWasRun= false;
37+
new MainRunner().runWithCheckForSystemExit(new Runnable() {
38+
public void run() {
39+
JUnitCore.main("org.junit.tests.running.core.CommandLineTest$Example");
40+
}
41+
});
3942
assertTrue(testWasRun);
4043
}
4144

src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import static org.junit.Assert.fail;
55
import org.junit.Test;
66
import org.junit.runner.JUnitCore;
7-
import org.junit.tests.TestSystem;
87

98
public class JUnitCoreReturnsCorrectExitCodeTest {
109

@@ -31,9 +30,12 @@ static public class Succeed {
3130
runClass(getClass().getName() + "$Succeed", 0);
3231
}
3332

34-
private void runClass(String className, int returnCode) {
35-
TestSystem system= new TestSystem();
36-
JUnitCore.runMainAndExit(system, className);
37-
assertEquals(returnCode, system.fCode);
33+
private void runClass(final String className, int returnCode) {
34+
Integer exitValue= new MainRunner().runWithCheckForSystemExit(new Runnable() {
35+
public void run() {
36+
JUnitCore.main(className);
37+
}
38+
});
39+
assertEquals(Integer.valueOf(returnCode), exitValue);
3840
}
3941
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package org.junit.tests.running.core;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.io.PrintStream;
5+
import java.security.Permission;
6+
7+
public class MainRunner {
8+
9+
private static class ExitException extends SecurityException {
10+
private static final long serialVersionUID= -9104651568237766642L;
11+
12+
private final int status;
13+
14+
public ExitException(int status) {
15+
super("");
16+
this.status= status;
17+
}
18+
19+
public int getStatus() {
20+
return status;
21+
}
22+
}
23+
24+
private static class NoExitSecurityManager extends SecurityManager {
25+
@Override
26+
public void checkPermission(Permission perm) {
27+
// allow anything.
28+
}
29+
30+
@Override
31+
public void checkPermission(Permission perm, Object context) {
32+
// allow anything.
33+
}
34+
35+
@Override
36+
public void checkExit(int status) {
37+
super.checkExit(status);
38+
throw new ExitException(status);
39+
}
40+
}
41+
42+
/**
43+
* Execute runnable.run(), preventing System.exit(). If System.exit() is called
44+
* in runnable.run(), the value is returned. If System.exit()
45+
* is not called, null is returned.
46+
*
47+
* @param runnable
48+
* @return null if System.exit() is not called, Integer.valueof(status) if not
49+
*/
50+
public Integer runWithCheckForSystemExit(Runnable runnable) {
51+
SecurityManager oldSecurityManager = System.getSecurityManager();
52+
System.setSecurityManager(new NoExitSecurityManager());
53+
PrintStream oldPrintStream = System.out;
54+
55+
System.setOut(new PrintStream(new ByteArrayOutputStream()));
56+
try {
57+
runnable.run();
58+
System.out.println("System.exit() not called, return null");
59+
return null;
60+
} catch (ExitException e) {
61+
System.out.println("System.exit() called, value=" + e.getStatus());
62+
return e.getStatus();
63+
} finally {
64+
System.setSecurityManager(oldSecurityManager);
65+
System.setOut(oldPrintStream);
66+
}
67+
}
68+
69+
}

0 commit comments

Comments
 (0)