Bug 457515: eclipse JUnit runner hangs when @Parameters name attribute contains a newline

- use a single escape method with a proper name
- avoid unnecessary multiple passes and regex search
- added test for , and \ in test name
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java
index e4e0d01..c721a20 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java
@@ -56,7 +56,7 @@
 	}
 
 	private void sendMessage(ITestIdentifier test, String status) {
-		fSender.sendMessage(status + getTestId(test) + ',' + RemoteTestRunner.replaceLineDelimiters(test.getName()));
+		fSender.sendMessage(status + getTestId(test) + ',' + RemoteTestRunner.escapeTestName(test.getName()));
 	}
 
 }
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java
index 582719e..63acd41 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java
@@ -507,29 +507,33 @@
 	}
 
 	public void visitTreeEntry(ITestIdentifier id, boolean b, int i) {
-		notifyTestTreeEntry(getTestId(id) + ',' + escapeComma(replaceLineDelimiters(id.getName())) + ',' + b + ',' + i);
+		notifyTestTreeEntry(getTestId(id) + ',' + escapeTestName(id.getName()) + ',' + b + ',' + i);
 	}
 
-	private String escapeComma(String s) {
-		if ((s.indexOf(',') < 0) && (s.indexOf('\\') < 0))
+	public static String escapeTestName(String s) {
+		if ((s.indexOf(',') < 0) && (s.indexOf('\\') < 0) && (s.indexOf('\r') < 0) && (s.indexOf('\n') < 0))
 			return s;
 		StringBuffer sb= new StringBuffer(s.length()+10);
 		for (int i= 0; i < s.length(); i++) {
 			char c= s.charAt(i);
-			if (c == ',')
+			if (c == ',') {
 				sb.append("\\,"); //$NON-NLS-1$
-			else if (c == '\\')
+			} else if (c == '\\') {
 				sb.append("\\\\"); //$NON-NLS-1$
-			else
+			} else if (c == '\r') {
+				if (i + 1 < s.length() && s.charAt(i + 1) == '\n') {
+					i++;
+				}
+				sb.append(' ');
+			} else if (c == '\n') {
+				sb.append(' ');
+			} else {
 				sb.append(c);
+			}
 		}
 		return sb.toString();
 	}
 
-	public static String replaceLineDelimiters(String name) {
-		return name.replaceAll("\\r\\n",  " ").replace('\n', ' ').replace('\r', ' '); //$NON-NLS-1$ //$NON-NLS-2$
-	}
-
 	// WANT: work in bug fixes since RC2?
 	private String getTestId(ITestIdentifier id) {
 		return fIds.getTestId(id);
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java
index 4f24f46..31e7640 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java
@@ -55,7 +55,7 @@
 	}
 
 	public String toString() {
-		return fStatus + " " + RemoteTestRunner.replaceLineDelimiters(fTest.getName()); //$NON-NLS-1$
+		return fStatus + " " + RemoteTestRunner.escapeTestName(fTest.getName()); //$NON-NLS-1$
 	}
 
 	public void setComparison(FailedComparison comparison) {
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/junit/tests/TestRunListenerTest4.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/junit/tests/TestRunListenerTest4.java
index cff5d15..fca14a8 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/junit/tests/TestRunListenerTest4.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/junit/tests/TestRunListenerTest4.java
@@ -275,7 +275,7 @@
 		assertEqualLog(expectedTree, actual);
 	}
 
-	public void testParametrizedWithNewLine() throws Exception {
+	public void testParametrizedWithEvilChars() throws Exception {
 		String source=
 				"package pack;\n"+
 				"\n"+
@@ -293,7 +293,7 @@
 				"\n"+
 				"	@Parameters(name = \"{index}: testEven({0})\")\n"+
 				"	public static Iterable<String[]> data() {\n"+
-				"		return Arrays.asList(new String[][] { { \"2\" }, { \"4\\n\" }, { \"6\\r\" }, { \"8\\r\\n\" } });\n"+
+				"		return Arrays.asList(new String[][] { { \"2\" }, { \"4\\n\" }, { \"6\\r\" }, { \"8\\r\\n\" }, { \"0\\\\,\" } });\n"+
 				"	}\n"+
 				"\n"+
 				"	@Parameter\n"+
@@ -307,8 +307,8 @@
 		IType aTestCase= createType(source, "pack", "ATestCase.java");
 
 		String[] expectedSequence= new String[] {
-				TestRunListeners.sessionAsString("ATestCase", ProgressState.COMPLETED, Result.OK, 0),
-				TestRunListeners.suiteAsString("pack.ATestCase", ProgressState.COMPLETED, Result.OK, null, 1),
+				TestRunListeners.sessionAsString("ATestCase", ProgressState.COMPLETED, Result.ERROR, 0),
+				TestRunListeners.suiteAsString("pack.ATestCase", ProgressState.COMPLETED, Result.ERROR, null, 1),
 				TestRunListeners.suiteAsString("[0: testEven(2)]", ProgressState.COMPLETED, Result.OK, null, 2),
 				TestRunListeners.testCaseAsString("testEven[0: testEven(2)]", "pack.ATestCase", ProgressState.COMPLETED, Result.OK, null, 3),
 				TestRunListeners.suiteAsString("[1: testEven(4 )]", ProgressState.COMPLETED, Result.OK, null, 2),
@@ -317,8 +317,10 @@
 				TestRunListeners.testCaseAsString("testEven[2: testEven(6 )]", "pack.ATestCase", ProgressState.COMPLETED, Result.OK, null, 3),
 				TestRunListeners.suiteAsString("[3: testEven(8 )]", ProgressState.COMPLETED, Result.OK, null, 2),
 				TestRunListeners.testCaseAsString("testEven[3: testEven(8 )]", "pack.ATestCase", ProgressState.COMPLETED, Result.OK, null, 3),
+				TestRunListeners.suiteAsString("[4: testEven(0\\,)]", ProgressState.COMPLETED, Result.ERROR, null, 2),
+				TestRunListeners.testCaseAsString("testEven[4: testEven(0\\,)]", "pack.ATestCase", ProgressState.COMPLETED, Result.ERROR, new FailureTrace("java.lang.NumberFormatException", null, null), 3),
 		};
-		String[] actual= runTreeTest(aTestCase, 10);
+		String[] actual= runTreeTest(aTestCase, 12);
 		assertEqualLog(expectedSequence, actual);
 	}
 }