From 346fe622c451d76a20607dd1182402aa56591cfa Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 6 Apr 2011 15:55:38 +0200 Subject: [PATCH] fork junit tests: initial --- .../junit/segments/OutputObjectRegistry.java | 13 +- .../junit/segments/SegmentedOutputStream.java | 9 ++ .../intellij/execution/junit/TestObject.java | 38 ++++- .../intellij/junit3/JUnit3IdeaTestRunner.java | 89 +++++++---- .../junit3/JUnit3OutputObjectRegistry.java | 5 +- .../src/com/intellij/junit3/TreeSender.java | 64 -------- .../intellij/junit4/JUnit4IdeaTestRunner.java | 105 +++++++------ .../junit4/JUnit4OutputObjectRegistry.java | 5 +- .../rt/execution/junit/ForkedVMWrapper.java | 117 +++++++++++++++ .../rt/execution/junit/IdeaTestRunner.java | 14 +- .../execution/junit/JUnitForkedStarter.java | 139 ++++++++++++++++++ .../rt/execution/junit/JUnitStarter.java | 20 ++- .../rt/execution/junit/TimeSender.java | 37 +++++ .../rt/execution/junit/TreeSender.java | 47 ++++++ 14 files changed, 539 insertions(+), 163 deletions(-) delete mode 100644 plugins/junit_rt/src/com/intellij/junit3/TreeSender.java create mode 100644 plugins/junit_rt/src/com/intellij/rt/execution/junit/ForkedVMWrapper.java create mode 100644 plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java create mode 100644 plugins/junit_rt/src/com/intellij/rt/execution/junit/TimeSender.java create mode 100644 plugins/junit_rt/src/com/intellij/rt/execution/junit/TreeSender.java diff --git a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java index 8b7132d6bd37..fba1ee3a5314 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java +++ b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java @@ -23,8 +23,9 @@ public abstract class OutputObjectRegistry { private int myLastIndex = 0; private PacketProcessor myMainTransport; - public OutputObjectRegistry(PacketProcessor transport) { - myMainTransport = transport; + protected OutputObjectRegistry(PacketProcessor mainTransport, int lastIndex) { + myLastIndex = lastIndex; + myMainTransport = mainTransport; } public String referenceTo(Object test) { @@ -97,4 +98,12 @@ public abstract class OutputObjectRegistry { public void forget(Object test) { myKnownKeys.remove(test); } + + public int getKnownObject(Object description) { + final Object o = myKnownKeys.get(description); + if (o instanceof String) { + return Integer.parseInt((String)o); + } + return 0; + } } diff --git a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/SegmentedOutputStream.java b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/SegmentedOutputStream.java index d6596347971a..f504d9d5227e 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/SegmentedOutputStream.java +++ b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/SegmentedOutputStream.java @@ -24,7 +24,12 @@ public class SegmentedOutputStream extends OutputStream implements PacketProcess private boolean myStarted = false; public SegmentedOutputStream(PrintStream transportStream) { + this(transportStream, false); + } + + public SegmentedOutputStream(PrintStream transportStream, boolean started) { myPrintStream = transportStream; + myStarted = started; try { flush(); } @@ -75,4 +80,8 @@ public class SegmentedOutputStream extends OutputStream implements PacketProcess writeNext(SegmentedStream.STARTUP_MESSAGE); myStarted = true; } + + public PrintStream getPrintStream() { + return myPrintStream; + } } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index fd0e508e95bc..e3f09c3dffcc 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -44,6 +44,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectRootManager; @@ -51,6 +52,8 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; @@ -61,12 +64,12 @@ import com.intellij.rt.execution.junit.JUnitStarter; import com.intellij.util.Function; import com.intellij.util.IJSwingUtilities; import com.intellij.util.PathUtil; +import com.intellij.util.lang.UrlClassLoader; import org.jetbrains.annotations.NotNull; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; +import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; import java.util.*; public abstract class TestObject implements JavaCommandLine { @@ -349,7 +352,32 @@ public abstract class TestObject implements JavaCommandLine { } protected JUnitProcessHandler createHandler() throws ExecutionException { - return JUnitProcessHandler.runJava(getJavaParameters(), myProject); + File tempFile = null; + try { + tempFile = FileUtil.createTempFile("command.line", ""); + myJavaParameters.getProgramParametersList().add("@@@" + tempFile.getAbsolutePath()); + } + catch (IOException e) { + LOG.error(e); + } + final JavaParameters javaParameters = getJavaParameters(); + try { + final PrintWriter writer = new PrintWriter(tempFile, "UTF-8"); + try { + writer.print(GeneralCommandLine.quoteParameter(((JavaSdkType)javaParameters.getJdk().getSdkType()).getVMExecutablePath(javaParameters.getJdk())) + " "); + writer.print(javaParameters.getVMParametersList().getParametersString() + " "); + writer.print("-classpath "); + writer.print(GeneralCommandLine.quoteParameter(javaParameters.getClassPath().getPathsString())); + } + finally { + writer.close(); + } + tempFile.deleteOnExit(); + } + catch (Exception e) { + LOG.error(e); + } + return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(javaParameters, myProject, true)); } diff --git a/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java b/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java index a9cf05ee5cd9..26562ca417b0 100644 --- a/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java +++ b/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java @@ -15,28 +15,37 @@ */ package com.intellij.junit3; -import com.intellij.rt.execution.junit.DeafStream; -import com.intellij.rt.execution.junit.IdeaTestRunner; -import com.intellij.rt.execution.junit.IDEAJUnitListener; -import com.intellij.rt.execution.junit.segments.PoolOfDelimiters; +import com.intellij.rt.execution.junit.*; +import com.intellij.rt.execution.junit.segments.OutputObjectRegistry; import com.intellij.rt.execution.junit.segments.SegmentedOutputStream; import junit.framework.*; import junit.textui.ResultPrinter; import junit.textui.TestRunner; import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; public class JUnit3IdeaTestRunner extends TestRunner implements IdeaTestRunner { private TestListener myTestsListener; private JUnit3OutputObjectRegistry myRegistry; private ArrayList myListeners; + private boolean mySendTree; public JUnit3IdeaTestRunner() { super(DeafStream.DEAF_PRINT_STREAM); } - public int startRunnerWithArgs(String[] args, ArrayList listeners) { + public int startRunnerWithArgs(String[] args, ArrayList listeners, boolean sendTree) { myListeners = listeners; + mySendTree = sendTree; + if (sendTree) { + setPrinter(new TimeSender(myRegistry)); + } + else { + setPrinter(new MockResultPrinter()); + } try { Test suite = TestRunnerUtil.getTestSuite(this, args); if (suite == null) return -1; @@ -60,12 +69,31 @@ public class JUnit3IdeaTestRunner extends TestRunner implements IdeaTestRunner { super.runFailed(message); } - public void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr) { - setPrinter(new TimeSender()); - myRegistry = new JUnit3OutputObjectRegistry(segmentedOut); + public void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr, int lastIdx) { + myRegistry = new JUnit3OutputObjectRegistry(segmentedOut, lastIdx); myTestsListener = new TestResultsSender(myRegistry); } + public Object getTestToStart(String[] args) { + return TestRunnerUtil.getTestSuite(this, args); + } + + public List getChildTests(Object description) { + return getTestCasesOf((Test)description); + } + + public OutputObjectRegistry getRegistry() { + return myRegistry; + } + + public String getStartDescription(Object child) { + final Test test = (Test)child; + if (test instanceof TestCase) { + return test.getClass().getName() + "," + ((TestCase)test).getName(); + } + return test.toString(); + } + protected TestResult createTestResult() { TestResult testResult = super.createTestResult(); testResult.addListener(myTestsListener); @@ -97,31 +125,40 @@ public class JUnit3IdeaTestRunner extends TestRunner implements IdeaTestRunner { return testResult; } - public TestResult doRun(Test suite, boolean wait) { - try { - TreeSender.sendSuite(myRegistry, suite); - } - catch (Exception e) { - //noinspection HardCodedStringLiteral - System.err.println("Internal Error occured."); - e.printStackTrace(System.err); + public TestResult doRun(Test suite, boolean wait) { //todo + if (mySendTree) { + try { + TreeSender.sendTree(this, suite); + } + catch (Exception e) { + //noinspection HardCodedStringLiteral + System.err.println("Internal Error occured."); + e.printStackTrace(System.err); + } } return super.doRun(suite, wait); } + static Vector getTestCasesOf(Test test) { + Vector testCases = new Vector(); + if (test instanceof TestRunnerUtil.SuiteMethodWrapper) { + test = ((TestRunnerUtil.SuiteMethodWrapper)test).getSuite(); + } + if (test instanceof TestSuite) { + TestSuite testSuite = (TestSuite)test; + + for (Enumeration each = testSuite.tests(); each.hasMoreElements();) { + Object childTest = each.nextElement(); + if (childTest instanceof TestSuite && !((TestSuite)childTest).tests().hasMoreElements()) continue; + testCases.addElement(childTest); + } + } + return testCases; + } + public static class MockResultPrinter extends ResultPrinter { public MockResultPrinter() { super(DeafStream.DEAF_PRINT_STREAM); } } - - private class TimeSender extends ResultPrinter { - public TimeSender() { - super(DeafStream.DEAF_PRINT_STREAM); - } - - protected void printHeader(long runTime) { - myRegistry.createPacket().addString(PoolOfDelimiters.TESTS_DONE).addLong(runTime).send(); - } - } } diff --git a/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java b/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java index 87deb5857916..2cf89bd7cc09 100644 --- a/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java +++ b/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java @@ -28,8 +28,9 @@ import junit.framework.TestCase; import junit.framework.TestSuite; public class JUnit3OutputObjectRegistry extends OutputObjectRegistry { - public JUnit3OutputObjectRegistry(PacketProcessor mainTransport) { - super(mainTransport); + + public JUnit3OutputObjectRegistry(PacketProcessor mainTransport, int lastIndex) { + super(mainTransport, lastIndex); } protected int getTestCont(Object test) { diff --git a/plugins/junit_rt/src/com/intellij/junit3/TreeSender.java b/plugins/junit_rt/src/com/intellij/junit3/TreeSender.java deleted file mode 100644 index caf4791548c9..000000000000 --- a/plugins/junit_rt/src/com/intellij/junit3/TreeSender.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed 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. - */ -package com.intellij.junit3; - -import com.intellij.rt.execution.junit.segments.OutputObjectRegistry; -import com.intellij.rt.execution.junit.segments.PoolOfDelimiters; -import com.intellij.rt.execution.junit.segments.Packet; -import junit.framework.Test; -import junit.framework.TestSuite; - -import java.util.*; - -public class TreeSender { - private static void sendNode(Test test, Packet packet, Collection objects) { - Vector testCases = getTestCasesOf(test); - packet.addObject(test, objects).addLong(testCases.size()); - for (int i = 0; i < testCases.size(); i++) { - Test nextTest = (Test)testCases.get(i); - sendNode(nextTest, packet, objects); - } - } - - private static Vector getTestCasesOf(Test test) { - Vector testCases = new Vector(); - if (test instanceof TestRunnerUtil.SuiteMethodWrapper) { - test = ((TestRunnerUtil.SuiteMethodWrapper)test).getSuite(); - } - if (test instanceof TestSuite) { - TestSuite testSuite = (TestSuite)test; - - for (Enumeration each = testSuite.tests(); each.hasMoreElements();) { - Object childTest = each.nextElement(); - if (childTest instanceof TestSuite && !((TestSuite)childTest).tests().hasMoreElements()) continue; - testCases.addElement(childTest); - } - } - return testCases; - } - - public static void sendSuite(OutputObjectRegistry registry, Test suite) { - Packet packet = registry.createPacket(); - packet.addString(PoolOfDelimiters.TREE_PREFIX); - Collection objects = new ArrayList(); - sendNode(suite, packet, objects); - for (Iterator iterator = objects.iterator(); iterator.hasNext();) { - ((Packet)iterator.next()).send(); - } - packet.addString("\n"); - packet.send(); - } -} diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java index 905d43be072d..a9d7be453853 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java @@ -15,14 +15,9 @@ */ package com.intellij.junit4; -import com.intellij.rt.execution.junit.DeafStream; -import com.intellij.rt.execution.junit.IDEAJUnitListener; -import com.intellij.rt.execution.junit.IdeaTestRunner; +import com.intellij.rt.execution.junit.*; import com.intellij.rt.execution.junit.segments.OutputObjectRegistry; -import com.intellij.rt.execution.junit.segments.Packet; -import com.intellij.rt.execution.junit.segments.PoolOfDelimiters; import com.intellij.rt.execution.junit.segments.SegmentedOutputStream; -import junit.textui.ResultPrinter; import org.junit.internal.requests.ClassRequest; import org.junit.internal.requests.FilterRequest; import org.junit.runner.*; @@ -37,49 +32,28 @@ public class JUnit4IdeaTestRunner implements IdeaTestRunner { private RunListener myTestsListener; private OutputObjectRegistry myRegistry; - private static void sendNode(Description test, Packet packet, Collection objectPackets) { - final ArrayList children = test.getChildren(); - packet.addObject(test, objectPackets).addLong(children.size()); - for (int i = 0; i < children.size(); i++) { - sendNode((Description)children.get(i), packet, objectPackets); - } - } + public int startRunnerWithArgs(String[] args, ArrayList listeners, boolean sendTree) { - public void sendTree(OutputObjectRegistry registry, Description suite) { - Packet packet = registry.createPacket(); - packet.addString(PoolOfDelimiters.TREE_PREFIX); - Set objects = new HashSet(); - sendNode(suite, packet, objects); - for (Iterator iterator = objects.iterator(); iterator.hasNext();) { - ((Packet)iterator.next()).send(); + final Request request = JUnit4TestRunnerUtil.buildRequest(args); + final Runner testRunner = request.getRunner(); + try { + Description description = testRunner.getDescription(); + if (request instanceof ClassRequest) { + description = getSuiteMethodDescription(request, description); + } + else if (request instanceof FilterRequest) { + description = getFilteredDescription(request, description); + } + if (sendTree) TreeSender.sendTree(this, description); + } + catch (Exception e) { + //noinspection HardCodedStringLiteral + System.err.println("Internal Error occured."); + e.printStackTrace(System.err); } - packet.addString("\n"); - packet.send(); - } - public int startRunnerWithArgs(String[] args, ArrayList listeners) { try { final JUnitCore runner = new JUnitCore(); - - final Request request = JUnit4TestRunnerUtil.buildRequest(args); - - final Runner testRunner = request.getRunner(); - try { - Description description = testRunner.getDescription(); - if (request instanceof ClassRequest) { - description = getSuiteMethodDescription(request, description); - } - else if (request instanceof FilterRequest) { - description = getFilteredDescription(request, description); - } - sendTree(myRegistry, description); - } - catch (Exception e) { - //noinspection HardCodedStringLiteral - System.err.println("Internal Error occured."); - e.printStackTrace(System.err); - } - runner.addListener(myTestsListener); for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { final IDEAJUnitListener junitListener = (IDEAJUnitListener)Class.forName((String)iterator.next()).newInstance(); @@ -101,7 +75,7 @@ public class JUnit4IdeaTestRunner implements IdeaTestRunner { })*/); long endTime = System.currentTimeMillis(); long runTime = endTime - startTime; - new TimeSender().printHeader(runTime); + if (sendTree) new TimeSender(myRegistry).printHeader(runTime); if (!result.wasSuccessful()) { return -1; @@ -152,18 +126,43 @@ public class JUnit4IdeaTestRunner implements IdeaTestRunner { } - public void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr) { - myRegistry = new JUnit4OutputObjectRegistry(segmentedOut); + public void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr, int lastIdx) { + myRegistry = new JUnit4OutputObjectRegistry(segmentedOut, lastIdx); myTestsListener = new JUnit4TestResultsSender(myRegistry); } - private class TimeSender extends ResultPrinter { - public TimeSender() { - super(DeafStream.DEAF_PRINT_STREAM); + public Object getTestToStart(String[] args) { + final Request request = JUnit4TestRunnerUtil.buildRequest(args); + final Runner testRunner = request.getRunner(); + Description description = null; + try { + description = testRunner.getDescription(); + if (request instanceof ClassRequest) { + description = getSuiteMethodDescription(request, description); + } + else if (request instanceof FilterRequest) { + description = getFilteredDescription(request, description); + } } + catch (Exception e) { + //noinspection HardCodedStringLiteral + System.err.println("Internal Error occured."); + e.printStackTrace(System.err); + } + return description; + } - protected void printHeader(long runTime) { - myRegistry.createPacket().addString(PoolOfDelimiters.TESTS_DONE).addLong(runTime).send(); - } + public List getChildTests(Object description) { + return ((Description)description).getChildren(); + } + + public OutputObjectRegistry getRegistry() { + return myRegistry; + } + + public String getStartDescription(Object child) { + final Description description = (Description)child; + final String methodName = description.getMethodName(); + return methodName != null ? description.getClassName() + "," + methodName : description.getClassName(); } } diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java index d628da9a062b..2d5366b44130 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java @@ -27,8 +27,9 @@ import org.junit.runner.Description; public class JUnit4OutputObjectRegistry extends OutputObjectRegistry { - public JUnit4OutputObjectRegistry(PacketProcessor mainTransport) { - super(mainTransport); + + public JUnit4OutputObjectRegistry(PacketProcessor mainTransport, int lastIndex) { + super(mainTransport, lastIndex); } protected int getTestCont(Object test) { diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/ForkedVMWrapper.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/ForkedVMWrapper.java new file mode 100644 index 000000000000..ba88cefb9a4c --- /dev/null +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/ForkedVMWrapper.java @@ -0,0 +1,117 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed 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. + */ +package com.intellij.rt.execution.junit; + +import java.io.*; + +/** +* User: anna +* Date: 4/6/11 +*/ +class ForkedVMWrapper extends DataOutputStream { + + private FileOutputStream myOutputStream; + private boolean myError; + + public ForkedVMWrapper(FileOutputStream outputStream, boolean error) throws FileNotFoundException { + super(outputStream); + myOutputStream = outputStream; + myError = error; + } + + public synchronized void write(int b) throws IOException { + printPrefix(); + myOutputStream.write(b); + } + + private void printPrefix() throws IOException { + myOutputStream.write("/K".getBytes()); + if (myError) { + myOutputStream.write("e".getBytes()); + } + else { + myOutputStream.write("o".getBytes()); + } + } + + public void write(byte[] b) throws IOException { + printPrefix(); + myOutputStream.write(b); + } + + public synchronized void write(byte[] b, int off, int len) throws IOException { + printPrefix(); + myOutputStream.write(b, off, len); + } + + public void close() throws IOException { + myOutputStream.close(); + } + + public void flush() throws IOException { + myOutputStream.flush(); + } + + public static void readWrapped(String path, PrintStream out, PrintStream err) throws IOException { + FileInputStream stream = new FileInputStream(path); + try { + boolean error = false; + boolean afterSymbol = false; + boolean afterM = false; + while (stream.available() > 0) { + char read = (char)stream.read(); + if (read == '/') { + afterSymbol = true; + continue; + } + if (afterSymbol) { + if (afterM) { + error = read == 'e'; + afterSymbol = false; + afterM = false; + continue; + } + if (read != 'K') { + if (error) { + err.write("/".getBytes()); + err.write(read); + } + else { + out.write("/".getBytes()); + out.write(read); + } + afterSymbol = false; + afterM = false; + continue; + } + else { + afterM = true; + continue; + } + } + if (error) { + err.write(read); + } + else { + out.write(read); + } + } + } + finally { + if (stream != null) stream.close(); + } + } +} diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java index 6dfe03aaecce..66a181a95336 100644 --- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java @@ -20,12 +20,22 @@ */ package com.intellij.rt.execution.junit; +import com.intellij.rt.execution.junit.segments.OutputObjectRegistry; import com.intellij.rt.execution.junit.segments.SegmentedOutputStream; +import org.junit.runner.Description; +import java.io.IOException; import java.util.ArrayList; +import java.util.List; public interface IdeaTestRunner { - int startRunnerWithArgs(String[] args, ArrayList listeners); - void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr); + int startRunnerWithArgs(String[] args, ArrayList listeners, boolean sendTree); + void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr, int lastIdx); + + Object getTestToStart(String[] args); + List getChildTests(Object description); + String getStartDescription(Object child); + + OutputObjectRegistry getRegistry(); } \ No newline at end of file diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java new file mode 100644 index 000000000000..54f8c6f01d00 --- /dev/null +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java @@ -0,0 +1,139 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed 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. + */ +package com.intellij.rt.execution.junit; + +import com.intellij.rt.execution.junit.segments.SegmentedOutputStream; + +import java.io.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** +* User: anna +* Date: 4/6/11 +*/ +public class JUnitForkedStarter { + private JUnitForkedStarter() { + } + + public static void main(String[] args) throws Exception { + final String testOutputPath = args[0]; + final int lastIdx = Integer.parseInt(args[1]); + final boolean isJUnit4 = args[2].equalsIgnoreCase("true"); + final String[] childTestDescription = {args[3]}; + final ArrayList listeners = new ArrayList(); + for (int i = 4, argsLength = args.length; i < argsLength; i++) { + listeners.add(args[i]); + } + + final File file = new File(testOutputPath); + if (!file.exists()) { + if (!file.createNewFile()) return; + } + final FileOutputStream stream = new FileOutputStream(testOutputPath); + PrintStream oldOut = System.out; + PrintStream oldErr = System.err; + try { + final PrintStream out = new PrintStream(new ForkedVMWrapper(stream, false)); + final PrintStream err = new PrintStream(new ForkedVMWrapper(stream, true)); + System.setOut(out); + System.setErr(err); + IdeaTestRunner testRunner = (IdeaTestRunner)JUnitStarter.getAgentClass(isJUnit4).newInstance(); + testRunner.setStreams(new SegmentedOutputStream(out, true), new SegmentedOutputStream(err, true), lastIdx); + System.exit(testRunner.startRunnerWithArgs(childTestDescription, listeners, false)); + } finally { + System.setOut(oldOut); + System.setErr(oldErr); + stream.close(); + } + } + + static int startForkedVMs(String[] args, + boolean isJUnit4, + ArrayList listeners, + SegmentedOutputStream out, + SegmentedOutputStream err, String commandline) throws Exception { + IdeaTestRunner testRunner = (IdeaTestRunner)JUnitStarter.getAgentClass(isJUnit4).newInstance(); + testRunner.setStreams(out, err, 0); + final Object description = testRunner.getTestToStart(args); + + TreeSender.sendTree(testRunner, description); + + long startTime = System.currentTimeMillis(); + + final List children = testRunner.getChildTests(description); + final boolean forkTillMethod = System.getProperty("idea.fork.junit.tests").equalsIgnoreCase("method"); + int result = processChildren(isJUnit4, listeners, out, err, commandline, testRunner, children, 0, forkTillMethod); + + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + new TimeSender(testRunner.getRegistry()).printHeader(runTime); + return result; + } + + private static int processChildren(boolean isJUnit4, + ArrayList listeners, + SegmentedOutputStream out, + SegmentedOutputStream err, + String commandline, IdeaTestRunner testRunner, List children, int result, boolean forkTillMethod) + throws IOException, InterruptedException { + for (int i = 0, argsLength = children.size(); i < argsLength; i++) { + final Object child = children.get(i); + final List childTests = testRunner.getChildTests(child); + if (childTests.isEmpty() || !forkTillMethod) { + result = Math.min(runChild(child, isJUnit4, listeners, out, err, commandline, testRunner, forkTillMethod), result); + } else { + result = Math.min(processChildren(isJUnit4, listeners, out, err, commandline, testRunner, childTests, result, forkTillMethod), result); + } + } + return result; + } + + private static int runChild(Object child, + boolean isJUnit4, + ArrayList listeners, + SegmentedOutputStream out, + SegmentedOutputStream err, + String commandline, IdeaTestRunner testRunner, + boolean forkTillMethod) + throws IOException, InterruptedException { + final File tempFile = File.createTempFile("fork", "test"); + final String testOutputPath = tempFile.getAbsolutePath(); + final int knownObject = testRunner.getRegistry().getKnownObject(child); + String command = commandline + " " + JUnitForkedStarter.class.getName()+ " " + testOutputPath + " " + (knownObject + (forkTillMethod ? 0 : 1)) + " " + + isJUnit4 + " " + testRunner.getStartDescription(child) ; + for (Iterator iterator = listeners.iterator(); iterator.hasNext(); ) { + command += " " + iterator.next(); + } + final Process exec = Runtime.getRuntime().exec(command); + int result = exec.waitFor(); + ForkedVMWrapper.readWrapped(testOutputPath, out.getPrintStream(), err.getPrintStream()); + // tempFile.deleteOnExit(); + return result; + } + + static String getForkedCommandLine() throws IOException { + final String path = System.getProperty("idea.fork.junit.tests") != null ? System.getProperty("idea.command.line") : null; + String commandline = null; + if (path != null) { + final BufferedReader reader = new BufferedReader(new FileReader(path)); + commandline = reader.readLine(); + reader.close(); + } + return commandline; + } +} diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java index debdd06441bb..3314c4c325a3 100644 --- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java @@ -16,6 +16,7 @@ package com.intellij.rt.execution.junit; import com.intellij.rt.execution.junit.segments.SegmentedOutputStream; + import java.io.*; import java.net.InetAddress; import java.net.Socket; @@ -74,7 +75,10 @@ public class JUnitStarter { isJunit4 = true; } else { - if (arg.startsWith("@@")) { + if (arg.startsWith("@@@")) { + System.setProperty("idea.command.line", arg.substring(3)); + continue; + } else if (arg.startsWith("@@")) { if (new File(arg.substring(2)).exists()) { try { final BufferedReader reader = new BufferedReader(new FileReader(arg.substring(2))); @@ -183,26 +187,28 @@ public class JUnitStarter { SegmentedOutputStream err) { PrintStream oldOut = System.out; PrintStream oldErr = System.err; - int result; try { System.setOut(new PrintStream(out)); System.setErr(new PrintStream(err)); + final String commandline = JUnitForkedStarter.getForkedCommandLine(); + if (commandline != null) { + return JUnitForkedStarter.startForkedVMs(args, isJUnit4, listeners, out, err, commandline); + } IdeaTestRunner testRunner = (IdeaTestRunner)getAgentClass(isJUnit4).newInstance(); - testRunner.setStreams(out, err); - result = testRunner.startRunnerWithArgs(args, listeners); + testRunner.setStreams(out, err, 0); + return testRunner.startRunnerWithArgs(args, listeners, true); } catch (Exception e) { e.printStackTrace(System.err); - result = -2; + return -2; } finally { System.setOut(oldOut); System.setErr(oldErr); } - return result; } - private static Class getAgentClass(boolean isJUnit4) throws ClassNotFoundException { + static Class getAgentClass(boolean isJUnit4) throws ClassNotFoundException { return isJUnit4 ? Class.forName("com.intellij.junit4.JUnit4IdeaTestRunner") : Class.forName("com.intellij.junit3.JUnit3IdeaTestRunner"); diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/TimeSender.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/TimeSender.java new file mode 100644 index 000000000000..9821f439574e --- /dev/null +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/TimeSender.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed 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. + */ +package com.intellij.rt.execution.junit; + +import com.intellij.rt.execution.junit.segments.OutputObjectRegistry; +import com.intellij.rt.execution.junit.segments.PoolOfDelimiters; +import junit.textui.ResultPrinter; + +/** +* User: anna +* Date: 4/5/11 +*/ +public class TimeSender extends ResultPrinter { + private final OutputObjectRegistry myRegistry; + + public TimeSender(OutputObjectRegistry registry) { + super(DeafStream.DEAF_PRINT_STREAM); + myRegistry = registry; + } + + public void printHeader(long runTime) { + myRegistry.createPacket().addString(PoolOfDelimiters.TESTS_DONE).addLong(runTime).send(); + } +} diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/TreeSender.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/TreeSender.java new file mode 100644 index 000000000000..df805ee8756b --- /dev/null +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/TreeSender.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed 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. + */ +package com.intellij.rt.execution.junit; + +import com.intellij.rt.execution.junit.segments.Packet; +import com.intellij.rt.execution.junit.segments.PoolOfDelimiters; + +import java.util.*; + +public class TreeSender { + + private TreeSender() { + } + + public static void sendTree(IdeaTestRunner runner, Object suite) { + Packet packet = runner.getRegistry().createPacket(); + packet.addString(PoolOfDelimiters.TREE_PREFIX); + Set objects = new HashSet(); + sendNode(runner, suite, packet, objects); + for (Iterator iterator = objects.iterator(); iterator.hasNext();) { + ((Packet)iterator.next()).send(); + } + packet.addString("\n"); + packet.send(); + } + + private static void sendNode(IdeaTestRunner runner, Object test, Packet packet, Collection objectPackets) { + final List children = runner.getChildTests(test); + packet.addObject(test, objectPackets).addLong(children.size()); + for (int i = 0; i < children.size(); i++) { + sendNode(runner, children.get(i), packet, objectPackets); + } + } +}