Bug 541110 - test case for the bug

This change adds a test for bug 541110. The test will run debug snippet
with a conditional breakpoint, so that the original bug conditions are
reproduced. Without the fixes for bug 541110, the test times out while
waiting for debug events.

Change-Id: Id84247bb2af9ab4e6e7b256edb629bea20dc3258
Signed-off-by: Simeon Andreev <simeon.danailov.andreev@gmail.com>
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug541110.java b/org.eclipse.jdt.debug.tests/java8/Bug541110.java
new file mode 100644
index 0000000..e0a76f9
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/Bug541110.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Simeon Andreev and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Simeon Andreev - initial API and implementation
+ *******************************************************************************/
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Bug541110 {
+
+	public final Map<String, String> map = new HashMap<>();
+	public void breakpointMethod(final String key, final String value) {
+		map.compute(key, (k, v) -> value);
+	}
+
+	public static void main(String[] args) {
+		Bug541110 delta = new Bug541110();
+		delta.breakpointMethod("someKey", "someValue");
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index 5d90622..2eed4e0 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -20,6 +20,9 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -29,9 +32,11 @@
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IMarkerDelta;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
@@ -464,6 +469,7 @@
 	    		cfgs.add(createLaunchConfiguration(jp, "EvalTestIntf18"));
 				cfgs.add(createLaunchConfiguration(jp, "EvalIntfSuperDefault"));
 				cfgs.add(createLaunchConfiguration(jp, "DebugHoverTest18"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug541110"));
 	    		loaded18 = true;
 	    		waitForBuild();
 	        }
@@ -745,7 +751,7 @@
 	}
 
 	/**
-	 * Returns the 'OneSeven' project.
+	 * Returns the 'OneEight' project.
 	 *
 	 * @return the test project
 	 */
@@ -2821,4 +2827,32 @@
 		return false;
 	}
 
+	protected void assertNoErrorMarkersExist() throws Exception {
+		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+		IProject[] projects = root.getProjects();
+		for (IProject project : projects) {
+			assertNoErrorMarkersExist(project);
+		}
+	}
+
+	protected void assertNoErrorMarkersExist(IProject project) throws Exception {
+		if (project.isAccessible()) {
+			IMarker[] projectMarkers = project.findMarkers(null, false, IResource.DEPTH_INFINITE);
+			List<IMarker> errorMarkers = Arrays.stream(projectMarkers).filter(marker -> isErrorMarker(marker)).collect(Collectors.toList());
+			String projectErrors = toString(errorMarkers);
+			assertEquals("found errors on project " + project + ":" + System.lineSeparator() + projectErrors, Collections.EMPTY_LIST, errorMarkers);
+		}
+	}
+
+	private static boolean isErrorMarker(IMarker marker) {
+		return marker.getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR;
+	}
+
+	private static String toString(Collection<IMarker> markers) {
+		StringBuilder markersInfo = new StringBuilder();
+		for (IMarker marker : markers) {
+			markersInfo.append(marker);
+		}
+		return markersInfo.toString();
+	}
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/LambdaBreakpointsTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/LambdaBreakpointsTests.java
new file mode 100644
index 0000000..6d9f336
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/LambdaBreakpointsTests.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Simeon Andreev and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Simeon Andreev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.breakpoints;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.testplugin.DebugEventWaiter;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.debug.tests.TestUtil;
+
+/**
+ * Tests conditional breakpoints.
+ */
+public class LambdaBreakpointsTests extends AbstractDebugTest {
+
+	/**
+	 * Constructor
+	 * @param name
+	 */
+	public LambdaBreakpointsTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return get18Project();
+	}
+
+
+	/**
+	 * Test for Bug 541110 - ClassCastException in Instruction.popValue and a zombie EventDispatcher$1 job afterwards
+	 *
+	 * We check that a specific conditional breakpoint on a line with a lambda expression does not cause a {@link ClassCastException}.
+	 */
+	public void testBug541110() throws Exception {
+		assertNoErrorMarkersExist();
+
+		String typeName = "Bug541110";
+		createConditionalLineBreakpoint(22, typeName, "map.get(key) != null", true);
+
+		try {
+			// The class cast exception causes a job which runs forever. So we will timeout when waiting for debug events, if the exception occurs.
+			ILaunchConfiguration config = getLaunchConfiguration(typeName);
+			DebugEventWaiter waiter = new DebugEventWaiter(DebugEvent.TERMINATE);
+			launchAndWait(config, waiter);
+			// Join running jobs in case the launch did go through, but we have the endless job.
+			TestUtil.waitForJobs(getName(), 1_000, 30_000, ProcessConsole.class);
+		} finally {
+			terminateAndRemoveJavaLaunches();
+			removeAllBreakpoints();
+		}
+	}
+
+	private void terminateAndRemoveJavaLaunches() {
+		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+		List<ILaunch> launches = Arrays.asList(launchManager.getLaunches());
+		for (ILaunch launch : launches) {
+			IDebugTarget debugTarget = launch.getDebugTarget();
+			if (debugTarget instanceof IJavaDebugTarget) {
+				terminateAndRemove((IJavaDebugTarget) debugTarget);
+			}
+		}
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/AbstractDebugViewTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/AbstractDebugViewTests.java
index 0583416..ac6f7ea 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/AbstractDebugViewTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/AbstractDebugViewTests.java
@@ -12,17 +12,10 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.stream.Collectors;
 
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspaceRoot;
-import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
@@ -258,35 +251,6 @@
 		});
 	}
 
-	protected void assertNoErrorMarkersExist() throws Exception {
-		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-		IProject[] projects = root.getProjects();
-		for (IProject project : projects) {
-			assertNoErrorMarkersExist(project);
-		}
-	}
-
-	protected void assertNoErrorMarkersExist(IProject project) throws Exception {
-		if (project.isAccessible()) {
-			IMarker[] projectMarkers = project.findMarkers(null, false, IResource.DEPTH_INFINITE);
-			List<IMarker> errorMarkers = Arrays.stream(projectMarkers).filter(marker -> isErrorMarker(marker)).collect(Collectors.toList());
-			String projectErrors = toString(errorMarkers);
-			assertEquals("found errors on project " + project + ":" + System.lineSeparator() + projectErrors, Collections.EMPTY_LIST, errorMarkers);
-		}
-	}
-
-	private static boolean isErrorMarker(IMarker marker) {
-		return marker.getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR;
-	}
-
-	private static String toString(Collection<IMarker> markers) {
-		StringBuilder markersInfo = new StringBuilder();
-		for (IMarker marker : markers) {
-			markersInfo.append(marker);
-		}
-		return markersInfo.toString();
-	}
-
 	protected ISelection getDebugViewSelection() throws Exception {
 		return debugView.getViewer().getSelection();
 	}