From 3b1c0c03e12555cf9e4b2a42e53648ce98ecd6bc Mon Sep 17 00:00:00 2001 From: cheeseng Date: Fri, 15 Jun 2012 22:00:47 +0800 Subject: [PATCH 1/6] Merged fix for output directories from rlegendi. --- .../ScalaTestLaunchDelegateTest.scala | 129 ++++++++++++++++++ .../launching/ScalaTestLaunchDelegate.scala | 24 +++- 2 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala diff --git a/org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala b/org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala new file mode 100644 index 0000000..1bb5781 --- /dev/null +++ b/org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala @@ -0,0 +1,129 @@ +package scala.tools.eclipse.scalatest.launching + +import org.junit.Test +import org.junit.Assert._ +import org.mockito.Mockito._ +import org.eclipse.debug.core.ILaunchConfiguration +import ScalaTestLaunchConstants._ +import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants +import org.eclipse.debug.internal.core.LaunchConfiguration +import org.mockito.Matchers +import org.mockito.Mockito +import org.junit.runner.RunWith +//import org.powermock.modules.junit4.PowerMockRunner +//import org.powermock.core.classloader.annotations.PrepareForTest +//import org.powermock.api.mockito.PowerMockito + +/** + * We need PowerMock because ScalaTestLaunchDelegate cannot be mocked with Mockito (its superclass is in a signed Jar file). + * + * @author rlegendi + */ +//@RunWith(classOf[PowerMockRunner]) +//@PrepareForTest(Array(classOf[ScalaTestLaunchDelegate])) +class ScalaTestLaunchDelegateTest { + + // -------------------------------------------------------------------------- + // Escaping test + + @Test(expected = classOf[IllegalArgumentException]) + def testEscapingForNullClassPathEntry() { + // TODO These might be static methods in a companion object + def delegate = new ScalaTestLaunchDelegate + delegate.escapeScalaTestClasspathComponent(null) + } + + @Test + def testEscapingForEmptyClassPathEntry() { + def delegate = new ScalaTestLaunchDelegate + def res = delegate.escapeScalaTestClasspathComponent("") + assertEquals("", res) + } + + @Test + def testEscapingForSimpleClassPathEntry() { + def delegate = new ScalaTestLaunchDelegate + def res = delegate.escapeScalaTestClasspathComponent("some.jar") + assertEquals("some.jar", res) + } + + @Test + def testEscapingForClassPathEntryWithSingleSpace() { + def delegate = new ScalaTestLaunchDelegate + + def res = delegate.escapeScalaTestClasspathComponent("Program files") + assertEquals("Program\\ files", res) + } + + @Test + def testEscapingForClassPathEntryWithDoubleSpaces() { + def delegate = new ScalaTestLaunchDelegate + + def res = delegate.escapeScalaTestClasspathComponent("Program files") + assertEquals("Program\\ \\ files", res) + } + + @Test + def testEscapingForClassPathEntryWithDoubleQuotes() { + def delegate = new ScalaTestLaunchDelegate + + def res = delegate.escapeScalaTestClasspathComponent("middle\"escaped") + assertEquals("middle\\\"escaped", res) + } + + // -------------------------------------------------------------------------- + // ScalaTest argument building test + + @Test(expected = classOf[IllegalArgumentException]) + def argsBuildingForNull() { + def delegate = new ScalaTestLaunchDelegate + delegate.getScalaTestArgs(null) + } + + private def evalScalaTestArgs(cps: String*): String = { + val config = mock(classOf[ILaunchConfiguration]) + + when(config.getAttribute(SCALATEST_LAUNCH_TYPE_NAME, TYPE_SUITE)).thenReturn(TYPE_PACKAGE) + when(config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "")).thenReturn("testpkg") + when(config.getAttribute(SCALATEST_LAUNCH_INCLUDE_NESTED_NAME, INCLUDE_NESTED_FALSE)).thenReturn(INCLUDE_NESTED_TRUE) + + //val delegate = mock(classOf[ScalaTestLaunchDelegate]) + val delegate = new ScalaTestLaunchDelegate() { + override def getClasspath(configuration: ILaunchConfiguration): Array[String] = cps.toArray + } + //doReturn(cps.toArray[String]).when(delegate).getClasspath(config) + + delegate.getScalaTestArgs(config) + } + + @Test + def argsBuildingForEmptyClassPath() { + val res = evalScalaTestArgs("") + assertEquals("-p \"\" -w testpkg", res) + } + + @Test + def argsBuildingForSingleClassPath() { + val res = evalScalaTestArgs("some.jar") + assertEquals("-p \"some.jar\" -w testpkg", res) + } + + @Test + def argsBuildingForMultipleSimpleClassPath() { + val res = evalScalaTestArgs("some.jar", "other.jar") + assertEquals("-p \"some.jar other.jar\" -w testpkg", res) + } + + @Test + def argsBuildingForFolderAndJarClassPath() { + val res = evalScalaTestArgs("some/folder", "and/", "some.jar") + assertEquals("-p \"some/folder and/ some.jar\" -w testpkg", res) + } + + @Test + def argsBuildingForSingleSpacedClassPath() { + val res = evalScalaTestArgs("some.jar", "and a spaced folder", "andSomething/else") + assertEquals("-p \"some.jar and\\ a\\ spaced\\ folder andSomething/else\" -w testpkg", res) + } + +} diff --git a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala index 805c0f8..e2b92c3 100644 --- a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala +++ b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala @@ -184,7 +184,27 @@ class ScalaTestLaunchDelegate extends AbstractJavaLaunchConfigurationDelegate { bootEntry.toList.map(_.getLocation()) } - private def getScalaTestArgs(configuration: ILaunchConfiguration): String = { + /** + * Simple utility function that processes a classpath element for the ScalaTest Runner class. + * + *

+ * Basically, the only task to do here is to escape each whitespace and double quote characters. + *

+ * + * @param comp a classpath component as a string + * @return a properly escaped version of parameter comp + * @see Runner (see section "Specifying a runpath") + * @author rlegendi + */ + // TODO Needs an expert's review + private[launching] def escapeScalaTestClasspathComponent(comp: String): String = { + require(comp != null) + comp.replaceAll("""\s""", """\\ """).replaceAll(""""""", """\\"""") + } + + private[launching] def getScalaTestArgs(configuration: ILaunchConfiguration): String = { + require(configuration != null) + val launchType = configuration.getAttribute(SCALATEST_LAUNCH_TYPE_NAME, TYPE_SUITE) launchType match { case TYPE_SUITE => @@ -214,7 +234,7 @@ class ScalaTestLaunchDelegate extends AbstractJavaLaunchConfigurationDelegate { case TYPE_PACKAGE => val packageName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "") val workspace = ResourcesPlugin.getWorkspace() - val outputDir = new File(workspace.getRoot.getLocation.toFile, JavaRuntime.getProjectOutputDirectory(configuration)).getAbsolutePath + val outputDir = getClasspath(configuration).foldLeft("")((acc, act) => acc + " " + escapeScalaTestClasspathComponent(act)).trim if (packageName.length > 0) { val includeNested = configuration.getAttribute(SCALATEST_LAUNCH_INCLUDE_NESTED_NAME, INCLUDE_NESTED_FALSE) if (includeNested == INCLUDE_NESTED_TRUE) From b45c54aa468b5a55ee7389fc959a3d0d3f14fe7d Mon Sep 17 00:00:00 2001 From: "Richard O. Legendi" Date: Mon, 18 Jun 2012 00:31:09 +0200 Subject: [PATCH 2/6] Fixed 'Workspace is closed.' issue --- .../eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala index e2b92c3..fc56b70 100644 --- a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala +++ b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala @@ -233,7 +233,8 @@ class ScalaTestLaunchDelegate extends AbstractJavaLaunchConfigurationDelegate { "" case TYPE_PACKAGE => val packageName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "") - val workspace = ResourcesPlugin.getWorkspace() + // Reference for the workspace should be omitted, tests fail with an java.lang.IllegalStateException: Workspace is closed. error message + //val workspace = ResourcesPlugin.getWorkspace() val outputDir = getClasspath(configuration).foldLeft("")((acc, act) => acc + " " + escapeScalaTestClasspathComponent(act)).trim if (packageName.length > 0) { val includeNested = configuration.getAttribute(SCALATEST_LAUNCH_INCLUDE_NESTED_NAME, INCLUDE_NESTED_FALSE) From 7ccdb2ca0575b32a60e6959916753b580b5da11d Mon Sep 17 00:00:00 2001 From: "Richard O. Legendi" Date: Mon, 18 Jun 2012 00:45:56 +0200 Subject: [PATCH 3/6] Removed all references to PowerMock --- .../launching/ScalaTestLaunchDelegateTest.scala | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala b/org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala index 1bb5781..801be2f 100644 --- a/org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala +++ b/org.scala-ide.sdt.scalatest.tests/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegateTest.scala @@ -10,17 +10,12 @@ import org.eclipse.debug.internal.core.LaunchConfiguration import org.mockito.Matchers import org.mockito.Mockito import org.junit.runner.RunWith -//import org.powermock.modules.junit4.PowerMockRunner -//import org.powermock.core.classloader.annotations.PrepareForTest -//import org.powermock.api.mockito.PowerMockito /** * We need PowerMock because ScalaTestLaunchDelegate cannot be mocked with Mockito (its superclass is in a signed Jar file). * * @author rlegendi */ -//@RunWith(classOf[PowerMockRunner]) -//@PrepareForTest(Array(classOf[ScalaTestLaunchDelegate])) class ScalaTestLaunchDelegateTest { // -------------------------------------------------------------------------- @@ -54,7 +49,7 @@ class ScalaTestLaunchDelegateTest { def res = delegate.escapeScalaTestClasspathComponent("Program files") assertEquals("Program\\ files", res) } - + @Test def testEscapingForClassPathEntryWithDoubleSpaces() { def delegate = new ScalaTestLaunchDelegate @@ -87,11 +82,9 @@ class ScalaTestLaunchDelegateTest { when(config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "")).thenReturn("testpkg") when(config.getAttribute(SCALATEST_LAUNCH_INCLUDE_NESTED_NAME, INCLUDE_NESTED_FALSE)).thenReturn(INCLUDE_NESTED_TRUE) - //val delegate = mock(classOf[ScalaTestLaunchDelegate]) val delegate = new ScalaTestLaunchDelegate() { override def getClasspath(configuration: ILaunchConfiguration): Array[String] = cps.toArray } - //doReturn(cps.toArray[String]).when(delegate).getClasspath(config) delegate.getScalaTestArgs(config) } From b7a16426eed5cf7a91e4d5a22be8644279850f1a Mon Sep 17 00:00:00 2001 From: "Richard O. Legendi" Date: Thu, 2 Aug 2012 18:52:50 +0200 Subject: [PATCH 4/6] Fixed absolute classpath entry --- org.scala-ide.sdt.scalatest/.classpath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.scala-ide.sdt.scalatest/.classpath b/org.scala-ide.sdt.scalatest/.classpath index 4e794b1..9c8994c 100644 --- a/org.scala-ide.sdt.scalatest/.classpath +++ b/org.scala-ide.sdt.scalatest/.classpath @@ -5,6 +5,6 @@ - + From 40041b6733290f1ef4a19b8d7fc6eda2e0c47c5b Mon Sep 17 00:00:00 2001 From: "Richard O. Legendi" Date: Fri, 3 Aug 2012 08:36:10 +0200 Subject: [PATCH 5/6] Added the test failure message to the stack trace table --- .../scalatest/ui/ScalaTestStackTrace.scala | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/ui/ScalaTestStackTrace.scala b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/ui/ScalaTestStackTrace.scala index ef8c218..bae333b 100644 --- a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/ui/ScalaTestStackTrace.scala +++ b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/ui/ScalaTestStackTrace.scala @@ -81,10 +81,23 @@ class ScalaTestStackTrace(parent: Composite, fTestRunner: ScalaTestRunnerViewPar } def handleOpen(e: SelectionEvent) { - val selectedIdx = fTable.getSelectionIndex - if (selectedIdx >= 0) { + // Note that everything is shifted by one (since the proper error message, if any) + // AND it should be pointing to the same location as the 0th element on the list + val offset = node match { + case tm: TestModel => tm.errorMessage match { + case Some(_) => -1 + case None => 0 + } + case _ => 0 + } + + // Selection index might return -1 in some exceptional cases (e.g., widget disposed) + if (fTable.getSelectionIndex >= 0) { + // If we get the first (annotation) line selected, its index would be -1 without the max call + // But this way it will be correctly pointing to the same location where the test failed + val selectedIdx = math.max(fTable.getSelectionIndex + offset, 0) fStackTraces match { - case Some(stackTraces) => + case Some(stackTraces) => val foldedStackTraces = getFoldedStackTraces(stackTraces) val stackTraceElement = foldedStackTraces(selectedIdx) val model = JavaCore.create(ResourcesPlugin.getWorkspace.getRoot) @@ -141,7 +154,16 @@ class ScalaTestStackTrace(parent: Composite, fTestRunner: ScalaTestRunnerViewPar stackTraces match { case Some(stackTraces) => val foldedStackTraces = getFoldedStackTraces(stackTraces) - val trace = foldedStackTraces.mkString("\n").trim + val testFailureMessage = node match { + case tm: TestModel => tm.errorMessage + case _ => None + } + + val trace = (testFailureMessage match { + case Some(m) => m + "\n" + case None => "" + }) + foldedStackTraces.mkString("\n").trim + fTable.setRedraw(false) fTable.removeAll() new TextualTrace(trace, getFilterPatterns) From dd2b3320b9c7bafdff1d3d2582677c91384b718a Mon Sep 17 00:00:00 2001 From: "Richard O. Legendi" Date: Fri, 3 Aug 2012 08:45:19 +0200 Subject: [PATCH 6/6] Solved some merging issues --- .../launching/ScalaTestLaunchDelegate.scala | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala index 3ea8652..c012c4d 100644 --- a/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala +++ b/org.scala-ide.sdt.scalatest/src/scala/tools/eclipse/scalatest/launching/ScalaTestLaunchDelegate.scala @@ -180,18 +180,6 @@ class ScalaTestLaunchDelegate extends AbstractJavaLaunchConfigurationDelegate { bootEntry.toList.map(_.getLocation()) } - /** - * Simple utility function that processes a classpath element for the ScalaTest Runner class. - * - *

- * Basically, the only task to do here is to escape each whitespace and double quote characters. - *

- * - * @param comp a classpath component as a string - * @return a properly escaped version of parameter comp - * @see Runner (see section "Specifying a runpath") - * @author rlegendi - */ // TODO Needs an expert's review private[launching] def escapeScalaTestClasspathComponent(comp: String): String = { require(comp != null) @@ -229,8 +217,6 @@ class ScalaTestLaunchDelegate extends AbstractJavaLaunchConfigurationDelegate { "" case TYPE_PACKAGE => val packageName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "") - // Reference for the workspace should be omitted, tests fail with an java.lang.IllegalStateException: Workspace is closed. error message - //val workspace = ResourcesPlugin.getWorkspace() val outputDir = getClasspath(configuration).foldLeft("")((acc, act) => acc + " " + escapeScalaTestClasspathComponent(act)).trim if (packageName.length > 0) { val includeNested = configuration.getAttribute(SCALATEST_LAUNCH_INCLUDE_NESTED_NAME, INCLUDE_NESTED_FALSE)