blob: 80e8e8cad51878c24c0b0aa6b55a6d99a99f18dc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 Nokia 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:
* Nokia - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.edc.debugger.tests;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager;
import org.eclipse.cdt.debug.core.breakpointactions.IBreakpointAction;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.breakpointactions.SkipAction;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Breakpoints;
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
import org.eclipse.cdt.debug.edc.services.Stack;
import org.eclipse.cdt.debug.edc.tests.TestUtils;
import org.eclipse.cdt.debug.ui.breakpointactions.LogAction;
import org.eclipse.cdt.debug.ui.breakpointactions.ResumeAction;
import org.eclipse.cdt.debug.ui.breakpointactions.SoundAction;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
import org.eclipse.cdt.dsf.debug.service.IStack;
import org.eclipse.core.runtime.IStatus;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
/**
TODO this really only tests run-control scenarios for breakpoint
actions. SkipAction & ResumeAction can be considered fully tested.
however, LogAction & SoundAction are only tested in terms of
coverage and not crashing. nothing checks the log to see if the
log was appropriately written, or if an expression was appropriatly
evaluated, and there's no automatic check for the Sound being played.
*/
public class BreakpointActionsTest {
private static final String BlackFlagWascana_cpp = "BlackFlagWascana.cpp"; //$NON-NLS-1$
private static final String dbg_simple_types_cpp = "dbg_simple_types.cpp"; //$NON-NLS-1$
private static final String BlackFlagWascana_cpp_path
= "C:\\myprog\\BlackFlagWascana\\src\\BlackFlagWascana.cpp"; //$NON-NLS-1$
private static final String dbg_breakpoints_cpp_path
= "C:\\myprog\\BlackFlagWascana\\src\\dbg_breakpoints.cpp"; //$NON-NLS-1$
private static final String dbg_derived_types_cpp_path
= "C:\\myprog\\BlackFlagWascana\\src\\dbg_derived_types.cpp"; //$NON-NLS-1$
private static final String dbg_memory_cpp_path
= "C:\\myprog\\BlackFlagWascana\\src\\dbg_memory.cpp"; //$NON-NLS-1$
private static final String dbg_rtti_cpp_path
= "C:\\myprog\\BlackFlagWascana\\src\\dbg_rtti.cpp"; //$NON-NLS-1$
private static final String dbg_simple_types_cpp_path
= "C:\\myprog\\BlackFlagWascana\\src\\dbg_simple_types.cpp"; //$NON-NLS-1$
/**
* these mementos are subject to change
*/
private static final String bpActionMemento
= "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>";
private static final String log8Data
= bpActionMemento + "<logData evalExpr=\"true\" message=\"3+5\"/>";
private static final String logHereData
= bpActionMemento + "<logData evalExpr=\"false\" message=\"here\"/>";
private static final String pause6Data
= bpActionMemento + "<resumeData pauseTime=\"6\"/>";
private static final String skip2Data
= bpActionMemento + "<skipData statements=\"2\"/>";
private static final String soundData
= bpActionMemento + "<soundData file=\"C:\\WINDOWS\\Media\\tada.wav\"/>";
static enum BPAction {
Log8(LogAction.class, "log8", log8Data),
LogHere(LogAction.class, "logHere", logHereData),
pause6(ResumeAction.class, "pause6", pause6Data),
Skip2(SkipAction.class, "skip2", skip2Data),
SoundTada(SoundAction.class, "soundTada", soundData);
final Class<? extends IBreakpointAction> c;
final String name;
final String memento;
BPAction(Class<? extends IBreakpointAction> c, String name, String memento) {
this.c = c;
this.name = name;
this.memento = memento;
}
Class<? extends IBreakpointAction> getActionClass() {
return c;
}
String getName() {
return name;
}
String getMemento() {
return memento;
}
}
static enum BPData {
main16(BlackFlagWascana_cpp_path, 16, BPAction.Skip2.getName()),
main18(BlackFlagWascana_cpp_path, 18, BPAction.Log8.getName()),
main19(BlackFlagWascana_cpp_path, 19, BPAction.Skip2.getName()),
main23(BlackFlagWascana_cpp_path, 23, BPAction.pause6.getName()),
main24(BlackFlagWascana_cpp_path, 24, BPAction.LogHere.getName()),
main25(BlackFlagWascana_cpp_path, 25, BPAction.LogHere.getName()+","+BPAction.SoundTada.getName()),
dbg_breakpoints(dbg_breakpoints_cpp_path, 56, null),
dbg_dervied_types(dbg_derived_types_cpp_path, 285, null),
dbg_memory(dbg_memory_cpp_path, 9, null),
dbg_rtti(dbg_rtti_cpp_path, 47, null),
dbg_simple_types(dbg_simple_types_cpp_path, 60, null)
;
final String file;
final int line;
final String actionPropString;
BPData(String file, int line, String actionPropString) {
this.file = file;
this.line = line;
this.actionPropString = actionPropString;
}
String getFile() {
return file;
}
int getLine() {
return line;
}
boolean hasActions() {
return actionPropString != null;
}
String getActions() {
return actionPropString;
}
}
static BreakpointActionManager bpActionMgr() {
return CDebugCorePlugin.getDefault().getBreakpointActionManager();
}
private static Breakpoints breakpointsService;
private static ArrayList<IBreakpoints.IBreakpointDMContext> bkpts;
private static BaseLaunchTest simpleLaunch;
private static IRunControl2 runControl;
private static IStack stackService;
@BeforeClass
public static void setUpClass() throws Exception {
simpleLaunch = new BaseLaunchTest() {
@Override
protected String getExeFileName() {
// This is the executable built by Cygwin gcc 3.4.4
// All source files are built from this folder:
// "C:\\myprog\\BlackFlagWascana\\src\\"
// Note we don't need any source file to perform the test.
//
// used because the locations of certain line numbers are known,
// not because there's no hardcoded break
return "BlackFlagMinGW_NoHardcodedBreak.exe"; //$NON-NLS-1$
}
@Override
protected IStack getStackService() {
return stackService;
}
@Override
protected boolean getStopAtMain() {
return true;
}
};
simpleLaunch.basicLaunch();
EDCServicesTracker edcTracker
= new EDCServicesTracker(
EDCDebugger.getBundleContext(), simpleLaunch.session.getId());
Assert.assertNotNull(edcTracker);
breakpointsService = edcTracker.getService(Breakpoints.class);
Assert.assertNotNull(breakpointsService);
runControl = edcTracker.getService(RunControl.class);
Assert.assertNotNull(runControl);
stackService = edcTracker.getService(Stack.class);
Assert.assertNotNull(stackService);
for (BPAction actionData : BPAction.values()) {
IBreakpointAction action
= actionData.getActionClass().getConstructor((Class[])null).newInstance((Object[])null);
action.setName(actionData.getName());
action.initializeFromMemento(actionData.getMemento());
bpActionMgr().addAction(action);
}
BPData[] allData = BPData.values();
bkpts = new ArrayList<IBreakpoints.IBreakpointDMContext>(allData.length);
TestUtils.waitForUIUpdate(1000);
}
private static IBreakpoints.IBreakpointDMContext setBreakpointWithAction(BPData bpData)
throws Exception, InterruptedException, ExecutionException,
TimeoutException {
String file = bpData.getFile();
int line = bpData.getLine();
final IBreakpoints.IBreakpointDMContext bp
= simpleLaunch.setUserBreakpoint(breakpointsService, file, line);
Assert.assertNotNull(bkpts);
if (bpData.hasActions()) {
final Map<String, Object> delta = new HashMap<String,Object>();
delta.put(BreakpointActionManager.BREAKPOINT_ACTION_ATTRIBUTE, bpData.getActions());
Query<IStatus> query = new Query<IStatus>() {
@Override
protected void execute(final DataRequestMonitor<IStatus> drm) {
breakpointsService.updateBreakpoint(bp, delta, drm);
}
};
simpleLaunch.session.getExecutor().execute(query);
query.get(1, TimeUnit.SECONDS);
}
return bp;
}
@AfterClass
public static void shutdown() {
for (final IBreakpoints.IBreakpointDMContext bpc : bkpts) {
try {
simpleLaunch.removeUserBreakpoint(breakpointsService, bpc);
} catch (Exception e) {
e.printStackTrace();
}
}
for (BPAction bpAction : BPAction.values()) {
IBreakpointAction action
= bpActionMgr().findBreakpointAction(bpAction.getName());
bpActionMgr().deleteAction(action);
}
TestUtils.shutdownDebugSession(simpleLaunch.launch, simpleLaunch.session);
bkpts = null;
breakpointsService = null;
simpleLaunch = null;
}
// for all tests, the target in waitRunToLine() has been semi-arbitrarily
// chosen as 26, because it's after the last test breakpoint
private void runToNextExpectedBreakpoint(int waitTime) throws Exception {
simpleLaunch.waitRunToLine(runControl, BlackFlagWascana_cpp_path, 26, 500);
TestUtils.waitForUIUpdate(waitTime);
}
// default 1/2 second wait
private void runToNextExpectedBreakpoint() throws Exception {
runToNextExpectedBreakpoint(500);
}
@Test
public void testBreakpointActionSkipActionEndingAtBreakpoint() throws Exception {
// bkpt16 has a skip2 skip action attached
// and thus skips over nested bkpts in dbg_breakpoints()
// & dbg_derived_types(). should end at bkpt at line 18 in main
// bkpt18 has a log action attached, which should execute
bkpts.add(setBreakpointWithAction(BPData.main16));
bkpts.add(setBreakpointWithAction(BPData.main18));
bkpts.add(setBreakpointWithAction(BPData.dbg_breakpoints));
bkpts.add(setBreakpointWithAction(BPData.dbg_dervied_types));
runToNextExpectedBreakpoint();
simpleLaunch.assertControlIsAt(BlackFlagWascana_cpp, "main", BPData.main18.getLine());
}
@Test
public void testBreakpointActionsSkipActionNoEndingAtBreakpoint() throws Exception {
// bkpt19 has a skip2 skip action attached,
// skips over nested breakpoints in dbg_memory() & dbg_rtti()
// should end in nested bkpt in dbg_simple_types()
bkpts.add(setBreakpointWithAction(BPData.main19));
bkpts.add(setBreakpointWithAction(BPData.dbg_memory));
bkpts.add(setBreakpointWithAction(BPData.dbg_rtti));
bkpts.add(setBreakpointWithAction(BPData.dbg_simple_types));
// was encountering occasional timing based errors when running this test.
// wait a little longer because the stack changes for this test where it
// is not changing for the other tests in this JUnit
runToNextExpectedBreakpoint(/* waitTime */ 1000);
simpleLaunch.assertControlIsAt(dbg_simple_types_cpp, "dbg_simple_types", BPData.dbg_simple_types.getLine());
}
@Test
public void testBreakpointActionsResumeActionPause6() throws Exception {
// bkpt23 has a pause6 resume action attached.
// so a check after 3 seconds should show we're still here
// and a check 6 seconds after that should show we're at the next bkpt
// should end at bkpt24
bkpts.add(setBreakpointWithAction(BPData.main23));
bkpts.add(setBreakpointWithAction(BPData.main24));
runToNextExpectedBreakpoint();
// we should be at our breakpoint right after it's hit
simpleLaunch.assertControlIsAt(BlackFlagWascana_cpp, "main", BPData.main23.getLine());
simpleLaunch.updateSuspendedFrame(3000); // half the length of the pause
// should still be at the same line (i.e. still pausing)
simpleLaunch.assertControlIsAt(BlackFlagWascana_cpp, "main", BPData.main23.getLine());
simpleLaunch.updateSuspendedFrame(4000); // the other half of the pause plus a little cushion
// should be done with the pause, and resumed to the next line
simpleLaunch.assertControlIsAt(BlackFlagWascana_cpp, "main", BPData.main24.getLine());
}
@Test
public void testBreakpointActionsSoundAction() throws Exception {
// bkpt25 has two actions attached
// ... uh, unsure how to really test if both were processed
bkpts.add(setBreakpointWithAction(BPData.main25));
runToNextExpectedBreakpoint();
Thread.sleep(100); // wait for sound to be played
simpleLaunch.assertControlIsAt(BlackFlagWascana_cpp, "main", BPData.main25.getLine());
}
}