blob: 23b3d446c110a0cbbe52814a23314b29449bd74e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Andrey Loskutov and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.debug.tests.ui;
import java.util.Arrays;
import java.util.Objects;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
import org.eclipse.debug.internal.ui.views.launch.LaunchView;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.tests.TestAgainException;
import org.eclipse.jdt.debug.tests.TestUtil;
import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.test.OrderedTestSuite;
import junit.framework.Test;
/**
* Tests for debug view.
*/
public class DebugViewTests extends AbstractDebugUiTests {
public static Test suite() {
return new OrderedTestSuite(DebugViewTests.class);
}
private LaunchView debugView;
private boolean showMonitorsOriginal;
public DebugViewTests(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
showMonitorsOriginal = jdiUIPreferences.getBoolean(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO);
jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, true);
resetPerspective(DebugViewPerspectiveFactory.ID);
debugView = sync(() -> (LaunchView) getActivePage().showView(IDebugUIConstants.ID_DEBUG_VIEW));
processUiEvents(100);
}
@Override
protected void tearDown() throws Exception {
IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, showMonitorsOriginal);
sync(() -> getActivePage().closeAllEditors(false));
processUiEvents(100);
super.tearDown();
}
public void testLastStackElementShown() throws Exception {
final String typeName = "DropTests";
final int expectedFramesNumber = 5;
final String expectedMethod = "method" + (expectedFramesNumber - 1);
IJavaBreakpoint bp = createMethodBreakpoint(typeName, expectedMethod, "()V", true, false);
bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
// Open editor to avoid UI overhead on suspend
sync(() -> openEditor(typeName + ".java"));
IJavaThread thread = null;
try {
thread = launchToBreakpoint(typeName);
processUiEvents(100);
// Prepare breakpoint and check everything below UI is OK
IBreakpoint hit = getBreakpoint(thread);
assertNotNull("Suspended, but not by breakpoint", hit);
assertTrue("Breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
IJavaStackFrame topFrame = (IJavaStackFrame) thread.getTopStackFrame();
assertNotNull("There should be a stackframe", topFrame);
assertEquals(expectedMethod, topFrame.getMethodName());
IStackFrame[] frames = topFrame.getThread().getStackFrames();
assertEquals(expectedFramesNumber, frames.length);
IJavaStackFrame mainFrame = (IJavaStackFrame) frames[expectedFramesNumber - 1];
assertEquals("First frame must be 'main'", "main", mainFrame.getMethodName());
// Let now all pending jobs proceed, ignore console jobs
sync(() -> TestUtil.waitForJobs(getName(), 2000, 10000, ProcessConsole.class));
processUiEvents(100);
// Get and check the selection form the tree, we expect only one method selected
TreeItem[] selected = getSelectedItemsFromDebugView(true);
Object[] selectedText = sync(() -> Arrays.stream(selected).map(x -> x.getText()).toArray());
if (selected.length != 1) {
if (Platform.getOS().equals(Platform.OS_MACOSX)) {
// skip this test on Mac - see bug 516024
return;
}
throw new TestAgainException("Unexpected selection: " + Arrays.toString(selectedText));
}
assertEquals("Unexpected selection: " + Arrays.toString(selectedText), 1, selected.length);
TreeItem selectedTreeItem = selected[selected.length - 1];
IJavaStackFrame selectedFrame = (IJavaStackFrame) sync(() -> {
Object data = selectedTreeItem.getData();
assertNotNull("No data for selected frame in the tree?", data);
assertEquals("Wrong object selected: " + data, JDIStackFrame.class, data.getClass());
return data;
});
// DropTests.method5() should be selected
assertEquals(selectedFrame.getMethodName(), topFrame.getMethodName());
// Now we inspect the children of the stopped thread (parent element of selected method)
TreeItem threadItem = sync(() -> selectedTreeItem.getParentItem());
TreeItem[] children = sync(() -> threadItem.getItems());
Object[] childrenText = sync(() -> Arrays.stream(children).map(x -> x.getText()).toArray());
// we expect to see one monitor + frames
final int expectedChildrenCount = expectedFramesNumber + 1;
if (childrenText.length != expectedChildrenCount) {
throw new TestAgainException("Not all frames shown: " + dumpFrames(childrenText));
}
assertEquals("Unexpected stack: " + dumpFrames(childrenText), expectedChildrenCount, childrenText.length);
// This is too unstable, see bug 516024 comment 10
// // Now we will check if the very first frame (main) is shown in the tree (on the bottom of the stack)
// Object firstFrame = childrenText[expectedChildrenCount - 1].toString();
//
// String frameLabel = firstFrame.toString();
// if (frameLabel.trim().isEmpty()) {
// // Some times (see bug 516024 comment 7) tree items are there but they are "empty", let restart test
// throw new TestAgainException("Tree children not rendered: " + dumpFrames(childrenText));
// }
//
// assertTrue("Unexpected first frame: " + firstFrame + ", ALL: "
// + dumpFrames(childrenText), frameLabel.contains("DropTests.main"));
}
finally {
terminateAndRemove(thread);
removeAllBreakpoints();
}
}
private String dumpFrames(Object[] childrenData) {
return Arrays.toString(Arrays.stream(childrenData).map(x -> Objects.toString(x)).toArray());
}
private TreeItem[] getSelectedItemsFromDebugView(boolean wait) throws Exception {
return sync(() -> {
Tree tree = (Tree) debugView.getViewer().getControl();
TreeItem[] selected = tree.getSelection();
if (!wait) {
return selected;
}
long start = System.currentTimeMillis();
// At least on GTK3 it takes some time until we see the viewer selection propagated to the SWT tree
while (selected.length != 1 && System.currentTimeMillis() - start < 10000) {
TreeViewer treeViewer = (TreeViewer) debugView.getViewer();
treeViewer.refresh(true);
processUiEvents(500);
TestUtil.log(IStatus.INFO, getName(), "Waiting for selection, current size: " + selected.length);
selected = tree.getSelection();
}
return selected;
});
}
}