/*******************************************************************************
* Copyright (c) 2012 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.debug.test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.debug.core.CDIDebugModel;
import org.eclipse.cdt.debug.core.model.ICBreakpoint;
import org.eclipse.cdt.debug.core.model.ICBreakpointType;
import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointsListener;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.tcf.debug.test.BreakpointsListener.EventTester;
import org.eclipse.tcf.debug.test.BreakpointsListener.EventType;
import org.eclipse.tcf.debug.test.services.RunControlCM.ContextState;
import org.eclipse.tcf.debug.test.util.Transaction;
import org.eclipse.tcf.internal.debug.model.TCFBreakpointsModel;
import org.eclipse.tcf.internal.debug.ui.launch.TCFLaunchContext;
import org.eclipse.tcf.protocol.Protocol;
import org.eclipse.tcf.services.IBreakpoints;
import org.eclipse.tcf.services.ILineNumbers.CodeArea;
import org.eclipse.tcf.services.ISymbols.Symbol;
import org.junit.Assert;
@SuppressWarnings("restriction")
public class BreakpointsTest extends AbstractTcfUITest
{
private BreakpointsListener fBpListener;
@Override
protected void setUp() throws Exception {
super.setUp();
fBpListener = new BreakpointsListener();
// CDT Breakpoint integration depends on the TCF-CDT breakpoint
// integration to be active. This is normally triggered by selecting
// a stack frame in the UI. Here force activation of the plugin
// artificially. None of the cdt integration packages are exported, so
// use the TCF Launch Context extension point indirectly to force the
// plugin to load.
TCFLaunchContext.getLaunchContext(null);
}
@Override
protected void tearDown() throws Exception {
fBpListener.dispose();
super.tearDown();
}
private CodeArea getFunctionCodeArea(final TestProcessInfo processInfo, String functionName) throws Exception {
return new Transaction<CodeArea>() {
@Override
protected CodeArea process() throws InvalidCacheException, ExecutionException {
ContextState state = validate ( fRunControlCM.getState(processInfo.fThreadId) );
String symId = validate ( fSymbolsCM.find(processInfo.fProcessId, new BigInteger(state.pc), "tcf_test_func0") );
Symbol sym = validate ( fSymbolsCM.getContext(symId) );
CodeArea[] area = validate ( fLineNumbersCM.mapToSource(
processInfo.fProcessId,
sym.getAddress(),
new BigInteger(sym.getAddress().toString()).add(BigInteger.valueOf(1))) );
return area[0];
}
}.get();
}
private ICLineBreakpoint createLineBreakpoint(String file, int line) throws CoreException, ExecutionException, InterruptedException {
// Initiate wait for the context changed event.
final Object contextChangedWaitKey = new Object();
Protocol.invokeAndWait(new Runnable() { public void run() {
fBreakpointsCM.waitContextAdded(contextChangedWaitKey);
}});
final ICLineBreakpoint bp = CDIDebugModel.createLineBreakpoint(file, ResourcesPlugin.getWorkspace().getRoot(), ICBreakpointType.REGULAR, line, true, 0, "", true);
Map<String, Object>[] addedBps = new Transaction<Map<String, Object>[]>() {
@Override
protected Map<String, Object>[] process() throws InvalidCacheException ,ExecutionException {
return validate(fBreakpointsCM.waitContextAdded(contextChangedWaitKey));
}
}.get();
fBpListener.setTester(new EventTester() {
public boolean checkEvent(EventType type, IBreakpoint testBp, Map<String, Object> deltaAttributes) {
return (type == EventType.CHANGED && bp == testBp);
}
});
fBpListener.waitForEvent();
Assert.assertEquals(1, addedBps.length);
Assert.assertEquals(1, bp.getMarker().getAttribute(ICBreakpoint.INSTALL_COUNT, -1));
return bp;
}
public void testContextAddedOnLineBrakpointCreate() throws Exception {
TestProcessInfo processInfo = initProcessModel("tcf_test_func0");
CodeArea bpCodeArea = getFunctionCodeArea(processInfo, "tcf_test_func0");
ICLineBreakpoint bp = createLineBreakpoint(bpCodeArea.file, bpCodeArea.start_line);
}
public void testForeignBreakpointCreate() throws Exception {
initProcessModel("tcf_test_func0");
final List<IBreakpoint> addedBps = Collections.synchronizedList(new ArrayList<IBreakpoint>());
IBreakpointsListener listener = new IBreakpointsListener() {
@Override
public void breakpointsAdded(IBreakpoint[] breakpoints) {
for (IBreakpoint bp : breakpoints) addedBps.add(bp);
addedBps.notify();
}
@Override
public void breakpointsChanged(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) {}
@Override
public void breakpointsRemoved(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) {
for (IBreakpoint bp : breakpoints) addedBps.remove(bp);
}
};
DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(listener);
try {
final String bpId = "testBp";
new Transaction<Map<String, Object>[]>() {
Map<String, Object> bp = new TreeMap<String, Object>();
{
bp.put(IBreakpoints.PROP_LOCATION, "tcf_test_func1");
bp.put(IBreakpoints.PROP_ID, bpId);
bp.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
// Bug 385965: test translation of prop_type attribute
bp.put(IBreakpoints.PROP_TYPE, IBreakpoints.TYPE_HARDWARE);
}
@Override
protected Map<String, Object>[] process() throws InvalidCacheException ,ExecutionException {
fBreakpointsCM.waitContextAdded(this);
validate( fBreakpointsCM.add(bp, this) );
return validate( fBreakpointsCM.waitContextAdded(this) );
}}.get(60, TimeUnit.SECONDS);
long timeout = System.currentTimeMillis() + TIMEOUT_DEFAULT;
wait: while(System.currentTimeMillis() < timeout) {
synchronized(addedBps) {
addedBps.wait(100);
for (IBreakpoint bp : addedBps) {
IMarker marker = bp.getMarker();
if (marker != null && bpId.equals(marker.getAttribute(TCFBreakpointsModel.ATTR_ID))) {
break wait;
}
}
}
}
if (System.currentTimeMillis() > timeout) {
Assert.fail("timed out");
}
} finally {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(listener);
}
}
}