/******************************************************************************* * Copyright (c) 2007, 2015 Ericsson 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: * Ericsson - Initial Implementation * Simon Marchi (Ericsson) - Move some tests from AsyncCompletionWaitor to Query *******************************************************************************/ package org.eclipse.cdt.tests.dsf.gdb.tests; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import org.eclipse.cdt.core.IAddress; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Query; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData; import org.eclipse.cdt.dsf.debug.service.IExpressions.IIndexedPartitionDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions2; import org.eclipse.cdt.dsf.debug.service.IExpressions2.CastInfo; import org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions3.IExpressionDMDataExtension; import org.eclipse.cdt.dsf.debug.service.IFormattedValues; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData; import org.eclipse.cdt.dsf.mi.service.ClassAccessor.MIExpressionDMCAccessor; import org.eclipse.cdt.dsf.mi.service.MIExpressions; import org.eclipse.cdt.dsf.mi.service.MIExpressions.MIExpressionDMC; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.tests.dsf.gdb.framework.AsyncCompletionWaitor; import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase; import org.eclipse.cdt.tests.dsf.gdb.framework.ServiceEventWaitor; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil; import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; import org.eclipse.cdt.utils.Addr32; import org.eclipse.cdt.utils.Addr64; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class MIExpressionsTest extends BaseParametrizedTestCase { private static final String EXEC_NAME = "ExpressionTestApp.exe"; private DsfSession fSession; private DsfServicesTracker fServicesTracker; protected IExpressions fExpService; private int fExprChangedEventCount = 0; private IExpressionDMContext fExprChangedCtx = null; private IExpressionDMContext globalExpressionCtx1 = null; private IExpressionDMContext globalExpressionCtx2 = null; @Override protected void setLaunchAttributes() { super.setLaunchAttributes(); setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + EXEC_NAME); } @Override public void doBeforeTest() throws Exception { super.doBeforeTest(); fSession = getGDBLaunch().getSession(); Runnable runnable = new Runnable() { @Override public void run() { fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); fExpService = fServicesTracker.getService(IExpressions.class); fSession.addServiceEventListener(MIExpressionsTest.this, null); clearExprChangedData(); } }; fSession.getExecutor().submit(runnable).get(); } @Override public void doAfterTest() throws Exception { super.doAfterTest(); if (fSession != null) { fSession.getExecutor().submit(()->fSession.removeServiceEventListener(MIExpressionsTest.this)).get(); } fExpService = null; if (fServicesTracker != null) { fServicesTracker.dispose(); } } // Handles ExpressionChangedEvent @DsfServiceEventHandler public void eventDispatched(IExpressionChangedDMEvent e) { fExprChangedEventCount++; fExprChangedCtx = e.getDMContext(); } // Clears the counters private void clearExprChangedData() { fExprChangedEventCount = 0; fExprChangedCtx = null; } // Returns the total number of events received private int getExprChangedCount() { return fExprChangedEventCount; } private IExpressionDMContext getExprChangedContext() { return fExprChangedCtx; } // ********************************************************************* // Below are the tests for the expression service. // ********************************************************************* /** * Test that we can correctly evaluate integer expressions. */ @Test public void testLiteralIntegerExpressions() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testLocals"); // Create a map of expressions and their expected values. Map<String, String[]> tests = new HashMap<String, String[]>(); tests.put("0 + 0 - 0", new String[] { "0x0", "0", "0", "0", "0", "0" }); tests.put("3 + 4", new String[] { "0x7", "07", "111", "7", "7", "7" }); tests.put("3 + 4 * 5", new String[] { "0x17", "027", "10111", "23", "23", "23" }); tests.put("5 * 3 + 4", new String[] { "0x13", "023", "10011", "19", "19", "19" }); tests.put("5 * (3 + 4)", new String[] { "0x23", "043", "100011", "35", "35", "35" }); tests.put("10 - 15", new String[] { "0xFFFFFFFB", "037777777773", "11111111111111111111111111111011", "-5", "-5", "-5" }); tests.put("10 + -15", new String[] { "0xFFFFFFFB", "037777777773", "11111111111111111111111111111011", "-5", "-5", "-5" }); executeExpressionSubTests(tests, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0)); } /** * Test that we can correctly evaluate floating-point expressions. */ @Test public void testLiteralFloatingPointExpressions() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testLocals"); // Create a map of expressions and their expected values. Map<String, String[]> tests = new HashMap<String, String[]>(); tests.put("3.14159 + 1.1111", new String[] { "0x4", "04", "100", "4", "4.2526", "4.2526" }); tests.put("100.0 / 3.0", new String[] { "0x21", "041", "100001", "33", "33.3333", "33.3333" }); tests.put("-100.0 / 3.0", new String[] { "0xffffffffffffffdf", "01777777777777777777737", "1111111111111111111111111111111111111111111111111111111111011111", "-33", "-33.3333", "-33.3333" }); tests.put("-100.0 / -3.0", new String[] { "0x21", "041", "100001", "33", "33.3333", "33.3333" }); executeExpressionSubTests(tests, false, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0)); tests.clear(); tests.put("100.0 / 0.5", new String[] { "0xc8", "0310", "11001000", "200", "200", "200" }); executeExpressionSubTests(tests, true, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0)); } /** * Test that we can correctly evaluate C expressions involving local * variables. */ @Test public void testLocalVariables() throws Throwable { // Run to the point where all local variables are initialized SyncUtil.runToLocation("testLocals"); MIStoppedEvent stoppedEvent = SyncUtil.step(16, StepType.STEP_OVER); // Create a map of expressions to expected values. Map<String, String[]> tests1 = new HashMap<String, String[]>(); tests1.put("lIntVar", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345", "12345" }); tests1.put("lDoubleVar", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345.123449999999", "12345.123449999999" }); tests1.put("lCharVar", new String[] { "0x6d", "0155", "1101101", "109", "109 'm'", "109 'm'" }); tests1.put("lBoolVar", new String[] { "0x0", "0", "0", "0", "false", "false" }); tests1.put("lIntArray[1]", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345", "12345" }); tests1.put("lDoubleArray[1]", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345.123449999999", "12345.123449999999" }); tests1.put("lCharArray[1]", new String[] { "0x6d", "0155", "1101101", "109", "109 'm'", "109 'm'" }); tests1.put("lBoolArray[1]", new String[] { "0x0", "0", "0", "0", "false", "false" }); tests1.put("*lIntPtr", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345", "12345" }); tests1.put("*lDoublePtr", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345.123449999999", "12345.123449999999" }); tests1.put("*lCharPtr", new String[] { "0x6d", "0155", "1101101", "109", "109 'm'", "109 'm'" }); tests1.put("*lBoolPtr", new String[] { "0x0", "0", "0", "0", "false", "false" }); tests1.put("lIntPtr2", new String[] { "0x1", "01", "1", "1", "0x1", "0x1" }); tests1.put("lDoublePtr2", new String[] { "0x2345", "021505", "10001101000101", "9029", "0x2345", "0x2345" }); // GDB says a char* is out of bounds, but not the other pointers??? // tests1.put("CharPtr2", new String[] { "0x1234", "011064", // "1001000110100", "4660", "0x1234" }); tests1.put("lBoolPtr2", new String[] { "0x123ABCDE", "02216536336", "10010001110101011110011011110", "305839326", "0x123ABCDE", "0x123ABCDE" }); executeExpressionSubTests(tests1, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0)); // Step into the method and stop until all new local variables are // initialized SyncUtil.step(StepType.STEP_INTO); stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); // Create a map of expressions to expected values. Map<String, String[]> tests2 = new HashMap<String, String[]>(); tests2.put("lIntVar", new String[] { "0x1a85", "015205", "1101010000101", "6789", "6789", "6789" }); tests2.put("lDoubleArray[1]", new String[] { "0x1a85", "015205", "1101010000101", "6789", "6789.6788999999999", "6789.6788999999999" }); tests2.put("lCharVar", new String[] { "0x69", "0151", "1101001", "105", "105 'i'", "105 'i'" }); tests2.put("*lCharPtr", new String[] { "0x69", "0151", "1101001", "105", "105 'i'", "105 'i'" }); tests2.put("lBoolPtr2", new String[] { "0xABCDE123", "025363360443", "10101011110011011110000100100011", "2882396451", "0xABCDE123","0xABCDE123" }); // check variables at current stack frame executeExpressionSubTests(tests2, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0)); // check previous stack frame executeExpressionSubTests(tests1, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1)); // Now return from the method and check that we see the // original variables. We must use the right context to restore the right stack frame stoppedEvent = SyncUtil.step(stoppedEvent.getDMContext(), StepType.STEP_RETURN); executeExpressionSubTests(tests1, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0)); } /** * This tests verifies that we can deal with variables in a subblock hiding * variables with the same name in the outer block. */ @Ignore("Sublocks do not work with GDB") @Test public void testSubBlock() throws Throwable { SyncUtil.runToLocation("testSubblock"); MIStoppedEvent stoppedEvent = SyncUtil.step(2, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); Map<String, String[]> tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x8", "010", "1000", "8", "8", "8" }); tests.put("b", new String[] { "0x1", "01", "1", "1", "1", "1" }); executeExpressionSubTests(tests, frameDmc); // Now enter a subblock with the same variable names SyncUtil.step(2, StepType.STEP_OVER); tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0xc", "014", "1100", "12", "12", "12" }); tests.put("b", new String[] { "0x1", "01", "1", "1", "1", "1" }); executeExpressionSubTests(tests, frameDmc); // Now step to change the b variable SyncUtil.step(1, StepType.STEP_OVER); tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0xc", "014", "1100", "12", "12", "12" }); tests.put("b", new String[] { "0xc", "014", "1100", "12", "12", "12" }); executeExpressionSubTests(tests, frameDmc); // Now exit the sub-block and check that we see the original a but the // same b SyncUtil.step(1, StepType.STEP_OVER); tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x8", "010", "1000", "8", "8", "8" }); tests.put("b", new String[] { "0xc", "014", "1100", "12", "12", "12" }); executeExpressionSubTests(tests, frameDmc); } /** * This tests verifies that we can obtain children properly. */ @Test public void testChildren() throws Throwable { assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_6_7); // Get the children of some variables MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testChildren"); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDMC = SyncUtil.createExpression(frameDmc, "f"); doTestChildren(exprDMC); // Now do a step and get the children again, to test the internal cache SyncUtil.step(1, StepType.STEP_OVER); doTestChildren(exprDMC); } /** * This test makes sure we get the right number of children. */ @Test public void testChildrenCount() throws Throwable { // Next we test that we can retrieve children count while reading the // value and vice-versa SyncUtil.runToLocation("testChildren"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // First we get the expected value of the array pointer. final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "f"); assertChildrenCount(exprDmc, 5); } /** * This test makes sure we get can tell if an expression has children based * on the expression data. */ @Test public void testHasChildrenInExpressionData() throws Throwable { SyncUtil.runToLocation("testChildren"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame( stoppedEvent.getDMContext(), 0); // First we get the expected value of the array pointer. final IExpressionDMContext exprDmc = SyncUtil.createExpression( frameDmc, "f"); Query<IExpressionDMData> query = new Query<IExpressionDMData>() { @Override protected void execute(DataRequestMonitor<IExpressionDMData> rm) { fExpService.getExpressionData(exprDmc, rm); } }; fExpService.getExecutor().submit(query); IExpressionDMData data = query.get(); IExpressionDMDataExtension dataExtension = (IExpressionDMDataExtension) data; assertThat("expression has children", dataExtension.hasChildren()); } /** * This test makes sure we properly deal with a GDB display bug. * See bug 320277 * * The following code causes a bug in GDB: * * class Base {}; * class BaseTest: public Base { * public: * BaseTest() {} // Removing this lines removes GDB's bug * void test() { return; } * }; * * We see the bug with the following commands: * -var-create - * this * -var-list-children var1 * -var-info-path-expression var1.BaseTest * -data-evaluate-expression "(*(Base*) this)" * * which we can reproduce by creating the children of this * and asking for the DETAILS_FORMAT of the var1.BaseTest child. */ @Test public void testBaseChildrenBug() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("BaseTest::test"); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // First we get 'this' and its children final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "this"); final IExpressionDMContext[] children = getChildren(exprDmc, new String[] { "Base", "Base" }); Query<FormattedValueDMData> query = new Query<FormattedValueDMData>() { @Override protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { FormattedValueDMContext dmc = fExpService.getFormattedValueContext(children[0], MIExpressions.DETAILS_FORMAT); fExpService.getFormattedExpressionValue(dmc, rm); } }; fExpService.getExecutor().submit(query); query.get(); // This second child is testing the fact that we could have the child named // the same as its type and we still want to be able to get the details without error. query = new Query<FormattedValueDMData>() { @Override protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { FormattedValueDMContext dmc = fExpService.getFormattedValueContext(children[1], MIExpressions.DETAILS_FORMAT); fExpService.getFormattedExpressionValue(dmc, rm); } }; fExpService.getExecutor().submit(query); query.get(); } /** * This test makes sure we properly deal with a GDB display bug and nested * children. See bug 320277. */ @Test public void testNestedBaseChildrenBug() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("BaseTest::test"); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // First we get 'this' and its children final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "this"); IExpressionDMContext[] children1 = getChildren(exprDmc, new String[] { "Base", "Base" }); final IExpressionDMContext[] children = getChildren(children1[0], new String[] { "nested", "pNested" }); final IExpressionDMContext[] childOfPointer = getChildren(children[1], new String[] { "*pNested" }); Query<FormattedValueDMData> query = new Query<FormattedValueDMData>() { @Override protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { FormattedValueDMContext dmc = fExpService.getFormattedValueContext(children[0], MIExpressions.DETAILS_FORMAT); fExpService.getFormattedExpressionValue(dmc, rm); } }; fExpService.getExecutor().submit(query); query.get(); query = new Query<FormattedValueDMData>() { @Override protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { FormattedValueDMContext dmc = fExpService.getFormattedValueContext(children[1], MIExpressions.DETAILS_FORMAT); fExpService.getFormattedExpressionValue(dmc, rm); } }; fExpService.getExecutor().submit(query); query.get(); query = new Query<FormattedValueDMData>() { @Override protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { FormattedValueDMContext dmc = fExpService.getFormattedValueContext(childOfPointer[0], MIExpressions.DETAILS_FORMAT); fExpService.getFormattedExpressionValue(dmc, rm); } }; fExpService.getExecutor().submit(query); query.get(); } /** * This test verifies that the ExpressionService can write to a variable. */ @Test public void testWriteVariable() throws Throwable { SyncUtil.runToLocation("testWrite"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "a[1]"); writeAndCheck(exprDmc, "987", IFormattedValues.DECIMAL_FORMAT, "987"); writeAndCheck(exprDmc, "16", IFormattedValues.HEX_FORMAT, "22"); writeAndCheck(exprDmc, "0x2e", IFormattedValues.HEX_FORMAT, "46"); writeAndCheck(exprDmc, "16", IFormattedValues.OCTAL_FORMAT, "14"); writeAndCheck(exprDmc, "022", IFormattedValues.OCTAL_FORMAT, "18"); writeAndCheck(exprDmc, "1011", IFormattedValues.BINARY_FORMAT, "11"); writeAndCheck(exprDmc, "0b1001", IFormattedValues.BINARY_FORMAT, "9"); writeAndCheck(exprDmc, "456", IFormattedValues.NATURAL_FORMAT, "456"); } /* * This method does a write and then a read to make sure the new value was * properly written. */ private void writeAndCheck(final IExpressionDMContext exprDmc, final String newValueFormatted, final String format, final String newValueInDecimal) throws Throwable { ServiceEventWaitor<IExpressionChangedDMEvent> eventWaitor = new ServiceEventWaitor<>( fSession, IExpressionChangedDMEvent.class); // Write the new value using its formatted value Query<Void> writeQuery = new Query<Void>() { @Override protected void execute(DataRequestMonitor<Void> rm) { fExpService.writeExpression(exprDmc, newValueFormatted, format, rm); } }; fExpService.getExecutor().submit(writeQuery); writeQuery.get(); IExpressionChangedDMEvent event = eventWaitor.waitForEvent(TestsPlugin.massageTimeout(1000)); assertThat(event.getDMContext(), is(exprDmc)); // Read the new value in decimal and check that it is what we expected Query<FormattedValueDMData> readQuery = new Query<FormattedValueDMData>() { @Override protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { FormattedValueDMContext dmc = fExpService.getFormattedValueContext(exprDmc, IFormattedValues.DECIMAL_FORMAT); fExpService.getFormattedExpressionValue(dmc, rm); } }; fExpService.getExecutor().submit(readQuery); String actualDecimalValue = readQuery.get().getFormattedValue(); assertThat(actualDecimalValue.toLowerCase(), is(newValueInDecimal.toLowerCase())); } /** * This tests verifies that we handle invalid formats properly for a write. */ @Test public void testWriteErrorFormat() throws Throwable { SyncUtil.runToLocation("testWrite"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "a[1]"); writeAndCheckError(exprDmc, "goodbye", IFormattedValues.DECIMAL_FORMAT); writeAndCheckError(exprDmc, "abggg", IFormattedValues.HEX_FORMAT); writeAndCheckError(exprDmc, "99", IFormattedValues.OCTAL_FORMAT); writeAndCheckError(exprDmc, "234", IFormattedValues.BINARY_FORMAT); writeAndCheckError(exprDmc, "hello", IFormattedValues.NATURAL_FORMAT); writeAndCheckError(exprDmc, "1", "ThisFormatDoesNotExist"); IExpressionDMContext notWritableExprDmc = SyncUtil.createExpression(frameDmc, "10+5"); writeAndCheckError(notWritableExprDmc, "1", IFormattedValues.NATURAL_FORMAT); } /* * This method does a write that should use an invalid value or format, and * verifies that the operation fails */ private void writeAndCheckError(final IExpressionDMContext exprDmc, final String invalidValueFormatted, final String format) throws Throwable { final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); // Write the new value using its formatted value fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.writeExpression(exprDmc, invalidValueFormatted, format, new RequestMonitor(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { wait.waitFinished(getStatus()); } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue("Got an OK status for an error test case. Should not be able to write value " + invalidValueFormatted + " in " + format, !wait.isOK()); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); } /** * This test tries multiple format reads during the same executor cycle, to * make sure the internal MI commands are sequenced properly. */ @Test public void testConcurrentReads() throws Throwable { // Next we test that we can read the value more than once // of the same variable object at the exact same time SyncUtil.runToLocation("testConcurrent"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a[0]"); wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("28")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format", null)); } } } }); wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equalsIgnoreCase("0x1c")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating hex format", null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); } /** * This test tries reads and listChildren during the same executor cycle, to * make sure the internal MI commands are sequenced properly. */ @Test public void testConcurrentReadChildren() throws Throwable { // Next we test that we can retrieve children while reading the value // and vice-versa SyncUtil.runToLocation("testConcurrent"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); // First we get the expected value of the array pointer. final IExpressionDMContext addrDmc = SyncUtil.createExpression(frameDmc, "&a"); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(addrDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { wait.setReturnInfo(getData()); } wait.waitFinished(getStatus()); } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); final String actualAddrStr = ((FormattedValueDMData) wait.getReturnInfo()).getFormattedValue(); wait.waitReset(); // Now perform the test fExpService.getExecutor().submit(new Runnable() { @Override public void run() { IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals(actualAddrStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format", null)); } } } }); wait.increment(); fExpService.getSubExpressions(exprDmc, new DataRequestMonitor<IExpressionDMContext[]>( fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { IExpressionDMContext[] children = getData(); int failedIndex = -1; for (int i = 0; i < 2; i++) { if (!children[i].getExpression().equals("a[" + i + "]")) { failedIndex = i; } } if (failedIndex != -1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting child number: " + failedIndex, null)); } else { wait.waitFinished(); } } } }); // Use different format to avoid triggering the cache wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals(actualAddrStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating hex format", null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); } /** * This test tries reads and getChildrenCount during the same executor * cycle, to make sure the internal MI commands are sequenced properly. */ @Test public void testConcurrentReadChildrenCount() throws Throwable { // Next we test that we can retrieve children count while reading the // value and vice-versa SyncUtil.runToLocation("testConcurrent"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); // First we get the expected value of the array pointer. final IExpressionDMContext addrDmc = SyncUtil.createExpression(frameDmc, "&a"); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(addrDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { wait.setReturnInfo(getData()); } wait.waitFinished(getStatus()); } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); final String actualAddrStr = ((FormattedValueDMData) wait.getReturnInfo()).getFormattedValue(); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals(actualAddrStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format", null)); } } } }); wait.increment(); fExpService.getSubExpressionCount(exprDmc, new DataRequestMonitor<Integer>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { int count = getData(); if (count != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting count for children. Got" + count + "instead of 2", null)); } else { wait.waitFinished(); } } } }); // Use different format to avoid triggering the cache wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals(actualAddrStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating hex format", null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); } /** * This test tries reads and writes during the same executor cycle, to make * sure the internal MI commands are sequenced properly. */ @Test public void testConcurrentReadWrite() throws Throwable { // Next we test that we can deal with a write request and read request // at // the same time and vice-versa SyncUtil.runToLocation("testConcurrent"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "a[1]"); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("32")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format, got " + getData().getFormattedValue() + " instead of 32", null)); } } } }); wait.increment(); fExpService.writeExpression(exprDmc, "56", IFormattedValues.NATURAL_FORMAT, new RequestMonitor( fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { wait.waitFinished(); } } }); // Use different format to avoid triggering the cache wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("0x38")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating hex format, got " + getData().getFormattedValue() + " instead of 0x38", null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); assertTrue("ExprChangedEvent problem: expected 1, received " + getExprChangedCount(), getExprChangedCount() == 1); exprDmc.equals(getExprChangedContext()); clearExprChangedData(); } /** * This test tries many different operations during the same executor cycle, * to make sure the internal MI commands are sequenced properly. */ @Test public void testConcurrentReadWriteChildren() throws Throwable { // Finally, we go nuts and request two reads, while requesting // a get children and get children count. // Note that we don't request a write, because a write is allowed to // go through at any time and we don't exactly know when it will // change the value we are reading. SyncUtil.runToLocation("testConcurrent"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "a[1]"); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("32")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format, got " + getData().getFormattedValue() + " instead of 32", null)); } } } }); wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("0x20")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating hex format, got " + getData().getFormattedValue() + " instead of 0x20", null)); } } } }); wait.increment(); fExpService.getSubExpressionCount(exprDmc, new DataRequestMonitor<Integer>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData() != 0) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting child count; expecting 0 got " + getData(), null)); } else { wait.waitFinished(); } } } }); wait.increment(); fExpService.getSubExpressions(exprDmc, new DataRequestMonitor<IExpressionDMContext[]>( fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().length != 0) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 0 got " + getData().length, null)); } else { wait.waitFinished(); } } } }); // Must use a different format or else the cache will be triggered wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.OCTAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("040")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating hex format, got " + getData().getFormattedValue() + " instead of 040", null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); exprDmc.equals(getExprChangedContext()); clearExprChangedData(); } /** * This test verifies that the ExpressionService caches the evaluation of an * expression in a specific format. It verifies this by: 1- reading a * variable 2- writing to that variable 3- reading the variable in a new * format and seeing the new value 4- reading the variable in the same * format as step 1 and seeing the old value cached Note that all above * steps must be done within the same Runnable submitted to the executor. * This allows the cache to be triggered before it is invalidated by a write * command, since the write command will need an new executor cycle to send * an MI command to the back-end */ @Test public void testWriteCache() throws Throwable { // Test the cache by changing a value but triggering a read before the // write clears the cache SyncUtil.runToLocation("testConcurrent"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "a[1]"); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("32")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format, got " + getData().getFormattedValue() + " instead of 32", null)); } } } }); wait.increment(); fExpService.writeExpression(exprDmc, "56", IFormattedValues.NATURAL_FORMAT, new RequestMonitor( fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { wait.waitFinished(); } } }); // Must use a different format or else the cache will be // triggered // This will prove that the write has changed the backend wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.OCTAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("070")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating hex format, got " + getData().getFormattedValue() + " instead of 070", null)); } } } }); // Test that the cache is triggered, giving us the old value // This happens because we are calling this operation on the // same executor run call. // NOTE that this is not a problem, because the writeExpression // will eventually // reset the cache (we'll test this below). wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("32")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format, got " + getData().getFormattedValue() + " instead of 32", null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); // Now that we know the writeExpressions completed and the cache was // reset, do a similar // request as above to see that the cache has indeed been reset wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("56")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format, got " + getData().getFormattedValue() + " instead of 56", null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); assertTrue("ExprChangedEvent problem: expected 1, received " + getExprChangedCount(), getExprChangedCount() == 1); exprDmc.equals(getExprChangedContext()); clearExprChangedData(); } /** * Test that we can correctly retrieve the address and type size of an * expression */ @Test public void testExprAddress() throws Throwable { SyncUtil.runToLocation("testAddress"); MIStoppedEvent stoppedEvent = SyncUtil.step(2, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "a"); final IExpressionDMContext exprDmc2 = SyncUtil.createExpression(frameDmc, "a_ptr"); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); // First get the address of 'a' through 'a_ptr' fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc2, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { wait.setReturnInfo(getData()); } wait.waitFinished(getStatus()); } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); String actualAddrStr = ((FormattedValueDMData) wait.getReturnInfo()).getFormattedValue(); wait.waitReset(); // Now check the address through our getAddressData checkAddressData(exprDmc, actualAddrStr, 4); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); } /** * Test that we can correctly evaluate C expressions involving global * variables. * * @return void */ @Test public void testGlobalVariables() throws Throwable { // Step to a stack level of 2 to be able to test differen stack frames MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("locals2"); // Create a map of expressions to expected values. Map<String, String[]> tests = new HashMap<String, String[]>(); // Global variables tests.put("gIntVar", new String[] { "0x21F", "01037", "1000011111", "543", "543", "543" }); tests.put("gDoubleVar", new String[] { "0x21F", "01037", "1000011111", "543", "543.54300000000001", "543.54300000000001" }); tests.put("gCharVar", new String[] { "0x67", "0147", "1100111", "103", "103 'g'", "103 'g'" }); tests.put("gBoolVar", new String[] { "0x0", "0", "0", "0", "false", "false" }); tests.put("gIntArray[1]", new String[] { "0x28E", "01216", "1010001110", "654", "654", "654" }); tests.put("gDoubleArray[1]", new String[] { "0x28E", "01216", "1010001110", "654", "654.32100000000003", "654.32100000000003" }); tests.put("gCharArray[1]", new String[] { "0x64", "0144", "1100100", "100", "100 'd'", "100 'd'" }); tests.put("gBoolArray[1]", new String[] { "0x0", "0", "0", "0", "false", "false" }); tests.put("*gIntPtr", new String[] { "0x21F", "01037", "1000011111", "543", "543", "543" }); tests.put("*gDoublePtr", new String[] { "0x21F", "01037", "1000011111", "543", "543.54300000000001", "543.54300000000001" }); tests.put("*gCharPtr", new String[] { "0x67", "0147", "1100111", "103", "103 'g'", "103 'g'" }); tests.put("*gBoolPtr", new String[] { "0x0", "0", "0", "0", "false", "false" }); tests.put("gIntPtr2", new String[] { "0x8", "010", "1000", "8", "0x8" , "0x8" }); tests.put("gDoublePtr2", new String[] { "0x5432", "052062", "101010000110010", "21554", "0x5432", "0x5432" }); // GDB says a char* is out of bounds, but not the other pointers??? // tests.put("gCharPtr2", new String[] { "0x4321", "041441", // "100001100100001", "17185", "0x4321" }); tests.put("gBoolPtr2", new String[] { "0x12ABCDEF", "02252746757", "10010101010111100110111101111", "313249263", "0x12ABCDEF", "0x12ABCDEF" }); // Try different stack frames executeExpressionSubTests(tests, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0)); executeExpressionSubTests(tests, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1)); executeExpressionSubTests(tests, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 2)); } /** * This test verifies that the ExpressionService can handle having a * variable with the same name in two different methods but at the same * stack depth. */ @Test public void testNamingSameDepth() throws Throwable { SyncUtil.runToLocation("testName1"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); Map<String, String[]> tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x1", "01", "1", "1", "1", "1" }); executeExpressionSubTests(tests, frameDmc); SyncUtil.runToLocation("testName2"); stoppedEvent = SyncUtil.step(1, StepType.STEP_INTO); frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x2", "02", "10", "2", "2", "2" }); executeExpressionSubTests(tests, frameDmc); SyncUtil.runToLocation("testName1"); stoppedEvent = SyncUtil.step(1, StepType.STEP_INTO); frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x3", "03", "11", "3", "3", "3" }); executeExpressionSubTests(tests, frameDmc); } /** * This test verifies that the ExpressionService can handle having a * variable with the same name in two methods that also have the same name */ @Test public void testNamingSameMethod() throws Throwable { SyncUtil.runToLocation("testSameName"); MIStoppedEvent stoppedEvent = SyncUtil.step(2, StepType.STEP_INTO); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); Map<String, String[]> tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x1", "01", "1", "1", "1" , "1" }); executeExpressionSubTests(tests, frameDmc); SyncUtil.step(StepType.STEP_RETURN); stoppedEvent = SyncUtil.step(2, StepType.STEP_INTO); frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x2", "02", "10", "2", "2", "2" }); executeExpressionSubTests(tests, frameDmc); SyncUtil.step(StepType.STEP_RETURN); stoppedEvent = SyncUtil.step(2, StepType.STEP_INTO); frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); tests = new HashMap<String, String[]>(); tests.put("a", new String[] { "0x3", "03", "11", "3", "3", "3" }); executeExpressionSubTests(tests, frameDmc); } /** * This test makes sure that if a request for expression values are made with * a thread selected, the top-most stack frame is used for evaluation */ @Test public void testThreadContext() throws Throwable { // Step to a stack level of 2 to be able to test differen stack frames SyncUtil.runToLocation("locals2"); MIStoppedEvent stoppedEvent = SyncUtil.step(StepType.STEP_OVER); // Create a map of expressions to expected values. Map<String, String[]> tests = new HashMap<String, String[]>(); // First make sure we have a different value on the other stack frame and that we select // a frame that is not the top frame tests.put("lIntVar", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345", "12345" }); executeExpressionSubTests(tests, SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1)); // Now check that we get the same values as the top stack when selecting the thread only tests = new HashMap<String, String[]>(); tests.put("lIntVar", new String[] { "0x1a85", "015205", "1101010000101", "6789", "6789" , "6789" }); executeExpressionSubTests(tests, stoppedEvent.getDMContext()); } /** * This test verifies that the ExpressionService can handle having a * child variable with the same name in two methods that also have the same name */ @Test public void testChildNamingSameMethod() throws Throwable { SyncUtil.runToLocation("testSameName"); MIStoppedEvent stoppedEvent = SyncUtil.step(4, StepType.STEP_INTO); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + getData().length, null)); } else { // now get the value of the child final String valueStr = "1"; final IExpressionDMContext child = getData()[0]; fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + child.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); SyncUtil.step(StepType.STEP_RETURN); stoppedEvent = SyncUtil.step(4, StepType.STEP_INTO); final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc2, "z"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + getData().length, null)); } else { // now get the value of the child final String valueStr = "2"; final IExpressionDMContext child = getData()[0]; fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + child.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); SyncUtil.step(StepType.STEP_RETURN); stoppedEvent = SyncUtil.step(4, StepType.STEP_INTO); final IFrameDMContext frameDmc3 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc3, "z"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + getData().length, null)); } else { // now get the value of the child final String valueStr = "3"; final IExpressionDMContext child = getData()[0]; fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + child.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * This test verifies that the ExpressionService properly updates * children variables, when we do not update the parent explicitly */ @Test public void testUpdatingChildren() throws Throwable { SyncUtil.runToLocation("testUpdateChildren"); MIStoppedEvent stoppedEvent = SyncUtil.step(2, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); doUpdateTest(frameDmc, 0); // Re-run the test to test out-of-scope update again SyncUtil.step(StepType.STEP_RETURN); stoppedEvent = SyncUtil.step(3, StepType.STEP_INTO); final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); doUpdateTest(frameDmc2, 100); // Re-run the test within a different method test out-of-scope updates SyncUtil.step(StepType.STEP_RETURN); stoppedEvent = SyncUtil.step(3, StepType.STEP_INTO); final IFrameDMContext frameDmc3 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); doUpdateTest(frameDmc3, 200); } public void doUpdateTest(final IFrameDMContext frameDmc, final int baseValue) throws Throwable { final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "a"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 1 got " + getData().length, null)); } else { // Now list the children of this child fExpService.getSubExpressions( getData()[0], new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { final IExpressionDMContext[] childDmcs = getData(); if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (childDmcs.length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + childDmcs.length, null)); } else { // now get the value of the two children for (int i =0; i<2; i++) { final String valueStr = Integer.toString(baseValue + i + 10); final int finali = i; wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(childDmcs[i], IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + childDmcs[finali].getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); // Now step to change the value of a.z.x and a.z.y and verify the changed values. // This will confirm that the parent "a" will have been properly updated // It is a better test to do it for two children because it tests concurrent update requests MIStoppedEvent stoppedEvent = SyncUtil.step(2, StepType.STEP_OVER); final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc2, "a"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 1 got " + getData().length, null)); } else { // Now list the children of this child fExpService.getSubExpressions( getData()[0], new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { final IExpressionDMContext[] childDmcs = getData(); if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (childDmcs.length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + childDmcs.length, null)); } else { // now get the value of the two children for (int i =0; i<2; i++) { final String valueStr = Integer.toString(baseValue + i + 20); final int finali = i; wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(childDmcs[i], IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + childDmcs[finali].getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * This test creates a variable object with children (not an array) and then gets these children * to be deleted because of a large number of other variable objects being created. * We then check that the expression service can handle a request for one of those deleted children, * which has a complex path. */ @Test public void testDeleteChildren() throws Throwable { assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_6_7); assumeGdbVersionLowerThen(ITestConstants.SUFFIX_GDB_7_3); SyncUtil.runToLocation("testDeleteChildren"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "f"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().length != 5) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 5 got " + getData().length, null)); } else { String childStr = "((bar) f)"; if (!getData()[0].getExpression().equals(childStr)) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got child " + getData()[0].getExpression() + " instead of " + childStr, null)); } else { // Now list the children of the first element fExpService.getSubExpressions( getData()[0], new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + getData().length, null)); } else { String childStr = "((((bar) f)).d)"; if (!getData()[0].getExpression().equals(childStr)) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got child " + getData()[0].getExpression() + " instead of " + childStr, null)); } else { wait.setReturnInfo(getData()[0]); wait.waitFinished(); } } } } }); } } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); final IExpressionDMContext deletedChildDmc = (IExpressionDMContext)wait.getReturnInfo(); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // Now create more than 1000 expressions to trigger the deletion of the children // that were created above for (int i=0; i<1100; i++) { IExpressionDMContext dmc = fExpService.createExpression(frameDmc, "a[" + i + "]"); wait.increment(); fExpService.getExpressionData( dmc, new DataRequestMonitor<IExpressionDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { wait.waitFinished(); } } }); } } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // Evaluate the expression of a child that we know is deleted to make sure // the expression service can handle that fExpService.getExpressionData( deletedChildDmc, new DataRequestMonitor<IExpressionDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { wait.waitFinished(); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * GDB 6.7 has a bug which will cause var-update not to show * the new value of 'a' if we switch the format to binary, * since binary of 3 is 11 which is the same as the old value * in natural format. Our expression service should work around this. * * int main() { * int a = 11; * a = 3; * return 0; * } */ @Test public void testUpdateGDBBug() throws Throwable { SyncUtil.runToLocation("testUpdateGDBBug"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); // This call will create the variable object in natural format and then change // it to binary to fetch the value fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(exprDmc, IFormattedValues.BINARY_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("1011")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating binary format, expected 1011 but got " + getData().getFormattedValue(), null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); // Now step to change the value of "a" and ask for it again stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc2, "a"); // This call will create the variable object in natural format and then change // it to binary to fetch the value fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(exprDmc, IFormattedValues.BINARY_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("11")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating binary format, expected 11 but got " + getData().getFormattedValue(), null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * var-update will not show a change if eval-expression is the same * in the current format. This is a problem for us because we don't * know if another format changed: * * int main() { * double a = 1.99; * a = 1.11; * } * * If a is displayed in anything but natural, both values of a are the same * and we won't know it changed in the natural format. * * The test below is in case GDB fixes var-update to keep track of the last * printed value through eval-expression. Until they do that, we do not have * a problem because of our caching: where, if we change formats since the last * var-update, it is impossible for us to set the format back * to the one of the last -var-update, since we already have that value in our cache. * So, the -var-update will show a change because of the new current format. * But if GDB has eval-expression reset their stored printed_value, this test * will fail and we'll know we have to fix something. */ @Test public void testUpdateIssue() throws Throwable { SyncUtil.runToLocation("testUpdateIssue"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); // check that we have the proper value wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("1.99")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating a, expected 1.99 but got " + getData().getFormattedValue(), null)); } } } }); // ask for hex to set the format to hex wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("0x1")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating a, expected 0x1 but got " + getData().getFormattedValue(), null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); // Now step to change the value of "a" and ask for it again but in the natural format stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc2, "a"); // trigger the var-update in the last format (hex) // then request the actual value in natural which should not be taken from the cache wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("1.22")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format, expected 1.22 but got " + getData().getFormattedValue(), null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * var-update will not show a change if eval-expression is the same * in the current format. This is a problem for us because we don't * know if another format changed: * * int main() { * struct { * double d; * } z; * * z.d = 1.0; * z.d = 1.22; * } * * If a is displayed in anything but natural, both values of a are the same * and we won't know it changed in the natural format. * This test uses a child to increase the value of the test. * Also, it avoids the cache saving us since we start with the 1.0 value * which is the same in natural and decimal */ @Test public void testUpdateIssue2() throws Throwable { SyncUtil.runToLocation("testUpdateIssue2"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 1 got " + getData().length, null)); } else { // check that we have the proper value // This will cache the value 1 in the natural format cache final String valueStr = "1"; globalExpressionCtx1 = getData()[0]; wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); // ask for decimal to set the format to decimal wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.DECIMAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); // Now step to change the value of "a" in natural but it remains the same in decimal SyncUtil.step(1, StepType.STEP_OVER); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // trigger the var-update in the last format (decimal) // then request the actual value in natural which should not be taken from the cache wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().getFormattedValue().equals("1.22")) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating natural format, expected 1.22 but got " + getData().getFormattedValue(), null)); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * This test verifies the state handling of a child variable object * to make sure that our locking scheme works even though we must deal * with an update call, internally */ @Test public void testConcurrentReadAndUpdateChild() throws Throwable { SyncUtil.runToLocation("testConcurrentReadAndUpdateChild"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); // Ask for one value to create the var object fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); wait.increment(); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 1 got " + getData().length, null)); } else { // now get the value of the child final String valueStr = "01"; globalExpressionCtx1 = getData()[0]; fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.OCTAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); // Now do two reads in two different formats // We need to make sure that the locking properly works although we are calling // the internal update method, which does affect the state of the object fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.BINARY_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { final String valueStr = "1"; if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.HEX_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { final String valueStr = "0x1"; if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * This test verifies some of the logic of dealing with out-of-scope variables. * This particular scenario is that we create a parent with a child and then * have them go out of scope. Then we request the child which will update the parent * and mark it as out-of-scope and recreate the child. The parent is not re-created. * We then ask twice for the parent which is already known to be out-of-scope and we need * to make sure that the parent is re-created once and only once. * We had a bug where we would enter an infinite loop in this case. */ @Test public void testConcurrentUpdateOutOfScopeChildThenParent() throws Throwable { SyncUtil.runToLocation("testConcurrentUpdateOutOfScopeChildThenParent"); MIStoppedEvent stoppedEvent = SyncUtil.step(2, StepType.STEP_INTO); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and its child globalExpressionCtx1 = fExpService.createExpression(frameDmc, "z"); wait.increment(); fExpService.getSubExpressions( globalExpressionCtx1, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 1 got " + getData().length, null)); } else { // now get the value of the child final String valueStr = "1"; globalExpressionCtx2 = getData()[0]; fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } } }); } }); wait.waitUntilDone(TestsPlugin.massageTimeout(5000)); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); SyncUtil.step(StepType.STEP_RETURN); stoppedEvent = SyncUtil.step(2, StepType.STEP_INTO); // Now step to another method to make the previous variable objects out-of-scope // then first request the child and then the parent. We want to test this order fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { final String valueStr = "2"; if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } }); wait.waitUntilDone(TestsPlugin.massageTimeout(5000)); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { final String valueStr = "{...}"; if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); // Ask a second time but in a different format, to avoid the cache wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.DECIMAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { final String valueStr = "{...}"; if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(valueStr)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + valueStr, null)); } } }); } }); wait.waitUntilDone(TestsPlugin.massageTimeout(5000)); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); //TODO although this test passes, the variable z is created twice, without being // deleted in GDB. We should fix this } /** * This test verifies that we properly update a pointer and its child since they can both * change and be reported by var-update */ @Test public void testUpdateOfPointer() throws Throwable { SyncUtil.runToLocation("testUpdateOfPointer"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final String firstValue = "1"; final String secondValue = "2"; final String thirdValue = "3"; final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + getData().length, null)); } else { // check that we have the proper value for both children globalExpressionCtx1 = getData()[0]; globalExpressionCtx2 = getData()[1]; // Get the value of the first child wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(firstValue)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + firstValue, null)); } } }); // Get the value of the second child wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { wait.setReturnInfo(getData().getFormattedValue()); wait.waitFinished(); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); final String pointerValue = (String)wait.getReturnInfo(); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // also get the child of the pointer fExpService.getSubExpressions( globalExpressionCtx2, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 1 got " + getData().length, null)); } else { // Get the value of the child of the pointer globalExpressionCtx2 = getData()[0]; fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(firstValue)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + firstValue, null)); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); // Now step to change the values of all the children stoppedEvent = SyncUtil.step(2, StepType.STEP_OVER); final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc2, "z"); fExpService.getSubExpressions( parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + getData().length, null)); } else { // check that we have the proper value for both children globalExpressionCtx1 = getData()[0]; globalExpressionCtx2 = getData()[1]; // Get the value of the first child wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(secondValue)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + secondValue, null)); } } }); // Get the value of the second child wait.increment(); fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (!getData().getFormattedValue().equals(pointerValue)) { // The value should have changed wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + " instead of some other value", null)); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // also get the child of the pointer fExpService.getSubExpressions( globalExpressionCtx2, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().length != 1) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 1 got " + getData().length, null)); } else { // Get the value of the child of the pointer globalExpressionCtx2 = getData()[0]; fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData().getFormattedValue().equals(thirdValue)) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + " instead of " + thirdValue, null)); } } }); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * This test verifies that we properly return if we can write to different expressions */ @Test public void testCanWrite() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testCanWrite"); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { final int exprCount = 5; final IExpressionDMContext dmcs[] = new IExpressionDMContext[exprCount]; final boolean expectedValues[] = new boolean[exprCount]; int exprIndex = 0; dmcs[exprIndex] = fExpService.createExpression(frameDmc, "a"); expectedValues[exprIndex] = true; exprIndex++; dmcs[exprIndex] = fExpService.createExpression(frameDmc, "b"); expectedValues[exprIndex] = true; exprIndex++; dmcs[exprIndex] = fExpService.createExpression(frameDmc, "c"); expectedValues[exprIndex] = false; exprIndex++; dmcs[exprIndex] = fExpService.createExpression(frameDmc, "d"); expectedValues[exprIndex] = false; exprIndex++; dmcs[exprIndex] = fExpService.createExpression(frameDmc, "d[1]"); expectedValues[exprIndex] = true; exprIndex++; for (int index = 0; index < exprCount; index++) { final int finalIndex = index; wait.increment(); fExpService.canWriteExpression( dmcs[finalIndex], new DataRequestMonitor<Boolean>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData() == expectedValues[finalIndex]) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed establishing proper canWrite for " + dmcs[finalIndex].getExpression() + ", got " + getData() + " instead of " + expectedValues[finalIndex], null)); } } }); } } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * This test verifies that we properly return if we can write to an expression * that is an L-Value or a Constant */ @Test public void testCanWriteLValue() throws Throwable { assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_6_8); MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testCanWrite"); // Re-use test final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { final int exprCount = 2; final IExpressionDMContext dmcs[] = new IExpressionDMContext[exprCount]; final boolean expectedValues[] = new boolean[exprCount]; int exprIndex = 0; dmcs[exprIndex] = fExpService.createExpression(frameDmc, "&a"); expectedValues[exprIndex] = false; exprIndex++; dmcs[exprIndex] = fExpService.createExpression(frameDmc, "1"); expectedValues[exprIndex] = false; exprIndex++; for (int index = 0; index < exprCount; index++) { final int finalIndex = index; wait.increment(); fExpService.canWriteExpression( dmcs[finalIndex], new DataRequestMonitor<Boolean>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else if (getData() == expectedValues[finalIndex]) { wait.waitFinished(); } else { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed establishing proper canWrite for " + dmcs[finalIndex].getExpression() + ", got " + getData() + " instead of " + expectedValues[finalIndex], null)); } } }); } } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * Executes a group of sub-tests. * * @param tests * A Map in which the key is an expression to evaluate and the * value is an array of expected values, one for each of the * formats supported by the Expressions service (hex, octal, * binary, decimal, natural, details). * @param exact * Indicates whether the natural and details format should * require an exact match to the expected value, or whether the * comparison should match only up to the number of characters * provided in the expected value. Where this is used is in * expressions that involve floating point calculation. Such * calculations are not exact (even when you'd think they should * be) and these tests cannot predict what exactly the result * will be. When this param is false, then we consider it a match * if, e.g., the gdb expression resolves to "1.23456789", but the * caller only supplied "1.2345". */ private void executeExpressionSubTests(final Map<String, String[]> tests, final boolean exact, IDMContext dmc) throws Throwable { // Now evaluate each of the above expressions and compare the actual // value against // the expected value. for (final String expressionToEvaluate : tests.keySet()) { // Get an IExpressionDMContext object representing the expression to // be evaluated. final IExpressionDMContext exprDMC = SyncUtil.createExpression(dmc, expressionToEvaluate); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); // Get the list of available format IDs for this expression and for // each one, // get the value of the expression fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.getAvailableFormats(exprDMC, new DataRequestMonitor<String[]>( fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { final String[] formatIds = getData(); // Now run the current sub-test using each of // the formats available for the type of // the expression in the sub-test. for (final String formatId : formatIds) { // Get a FormattedValueCMContext object for // the expression-formatID pair. final FormattedValueDMContext valueDmc = fExpService.getFormattedValueContext( exprDMC, formatId); // Increment the number of completed // requests to wait for, since we will send // multiple concurrent requests wait.increment(); // Evaluate the expression represented by // the FormattedValueDMContext object // This actually evaluates the expression. fExpService.getFormattedExpressionValue(valueDmc, new DataRequestMonitor<FormattedValueDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { // Get the // FormattedValueDMData // object from the waiter. FormattedValueDMData exprValueDMData = getData(); final String[] expectedValues = tests.get(expressionToEvaluate); // Check the value of the expression for correctness. String actualValue = exprValueDMData.getFormattedValue(); String expectedValue; if (formatId.equals(IFormattedValues.HEX_FORMAT)) expectedValue = expectedValues[0]; else if (formatId.equals(IFormattedValues.OCTAL_FORMAT)) expectedValue = expectedValues[1]; else if (formatId.equals(IFormattedValues.BINARY_FORMAT)) expectedValue = expectedValues[2]; else if (formatId.equals(IFormattedValues.DECIMAL_FORMAT)) expectedValue = expectedValues[3]; else if (formatId.equals(IFormattedValues.NATURAL_FORMAT)) expectedValue = expectedValues[4]; else if (formatId.equals(MIExpressions.DETAILS_FORMAT)) expectedValue = expectedValues[5]; else expectedValue = "[Unrecognized format ID: " + formatId + "]"; if ((exact == false) && (formatId.equals(IFormattedValues.NATURAL_FORMAT) || formatId.equals(MIExpressions.DETAILS_FORMAT)) && (expectedValue.length() < actualValue.length())) { actualValue = actualValue.substring(0, expectedValue.length()); } if (actualValue.equalsIgnoreCase(expectedValue)) { wait.waitFinished(); } else { String errorMsg = "Failed to correctly evalutate '" + expressionToEvaluate + "': expected '" + expectedValue + "', got '" + actualValue + "'"; wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, errorMsg, null)); } } } }); } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); } } private void executeExpressionSubTests(final Map<String, String[]> tests, IDMContext dmc) throws Throwable { executeExpressionSubTests(tests, true, dmc); } private boolean addressesEqual(IExpressionDMAddress addrToTest, String addrStr, int size) { IAddress addr; if (addrStr.length() <= 10) { addr = new Addr32(addrStr); } else { addr = new Addr64(addrStr); } return addrToTest.getAddress().equals(addr) && addrToTest.getSize() == size; } private void checkAddressData(final IExpressionDMContext dmc, String actualAddrStr, int actualAddrSize) throws Throwable { final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.getExpressionAddressData(dmc, new DataRequestMonitor<IExpressionDMAddress>(fExpService .getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { wait.setReturnInfo(getData()); } wait.waitFinished(getStatus()); } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); IExpressionDMAddress addr = (IExpressionDMAddress)wait.getReturnInfo(); assertTrue("Unable to get address", addr != null); if (addr != null) { assertTrue("Received wrong address of " + addr.toString() + " instead of (" + actualAddrStr + ", " + actualAddrSize + ")", addressesEqual(addr, actualAddrStr, actualAddrSize)); } } private void doTestChildren(IExpressionDMContext exprDMC) throws Throwable { IExpressionDMContext[] children = getChildren(exprDMC, new String[] {"bar", "bar2", "a", "b", "c"}); // f.bar IExpressionDMContext[] children1 = getChildren(children[0], new String[] {"d", "e"}); // f.bar.d getChildren(children1[0], new String[0]); // f.bar.e IExpressionDMContext[] children2 = getChildren(children1[1], new String[] {"e[0]", "e[1]"}); // f.bar.e[0] getChildren(children2[0], new String[0]); // f.bar.e[1] getChildren(children2[1], new String[0]); // f.bar2 children1 = getChildren(children[1], new String[] {"f", "g"}); // f.bar2.f getChildren(children1[0], new String[0]); // f.bar2.g children2 = getChildren(children1[1], new String[] {"g[0]", "g[1]"}); // f.bar2.g[0] getChildren(children2[0], new String[0]); // f.bar2.g[1] getChildren(children2[1], new String[0]); // f.a children1 = getChildren(children[2], new String[] {"a[0]", "a[1]"}); // f.a[0] getChildren(children1[0], new String[0]); // f.a[1] getChildren(children1[1], new String[0]); // f.b children1 = getChildren(children[3], new String[] {"d", "e"}); // f.b.d getChildren(children1[0], new String[0]); // f.b.e children2 = getChildren(children1[1], new String[] {"e[0]", "e[1]"}); // f.b.e[0] getChildren(children2[0], new String[0]); // f.b.e[1] getChildren(children2[1], new String[0]); // f.c getChildren(children[4], new String[0]); assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), getExprChangedCount() == 0); } // This method tests IExspressions.getSubExpressions(IExpressionDMC, DRM); protected IExpressionDMContext[] getChildren( final IExpressionDMContext parentDmc, String[] expectedValues) throws Throwable { final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.getSubExpressions(parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { wait.setReturnInfo(getData()); } wait.waitFinished(getStatus()); } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); IExpressionDMContext[] childDmcs = (IExpressionDMContext[]) wait.getReturnInfo(); String[] childExpressions = new String[childDmcs.length]; MIExpressionDMCAccessor[] childDmcsAccessor = new MIExpressionDMCAccessor[childDmcs.length]; // Convert to a MIExpressionDMCAccessor to be able to call getRelativeExpression // Also convert to String[] to be able to use Arrays.toString() for (int i = 0; i < childExpressions.length; i++) { childDmcsAccessor[i] = new MIExpressionDMCAccessor(childDmcs[i]); childExpressions[i] = childDmcsAccessor[i].getRelativeExpression(); } assertTrue("Expected " + Arrays.toString(expectedValues) + " but got " + Arrays.toString(childExpressions), expectedValues.length == childExpressions.length); for (int i = 0; i < childDmcsAccessor.length; i++) { assertEquals(expectedValues[i], childDmcsAccessor[i].getRelativeExpression()); } return childDmcs; } // This method tests IExpressions.getSubExpressions(IExpressionDMC, int, int, DRM); protected IExpressionDMContext[] getChildren( final IExpressionDMContext parentDmc, final int startIndex, final int length, String[] expectedValues) throws Throwable { final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { fExpService.getSubExpressions( parentDmc, startIndex, length, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { wait.setReturnInfo(getData()); } wait.waitFinished(getStatus()); } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); IExpressionDMContext[] childDmcs = (IExpressionDMContext[]) wait.getReturnInfo(); String[] childExpressions = new String[childDmcs.length]; MIExpressionDMCAccessor[] childDmcsAccessor = new MIExpressionDMCAccessor[childDmcs.length]; // Convert to a MIExpressionDMCAccessor to be able to call getRelativeExpression // Also convert to String[] to be able to use Arrays.toString() for (int i = 0; i < childExpressions.length; i++) { childDmcsAccessor[i] = new MIExpressionDMCAccessor(childDmcs[i]); childExpressions[i] = childDmcsAccessor[i].getRelativeExpression(); } assertTrue("Expected " + Arrays.toString(expectedValues) + " but got " + Arrays.toString(childExpressions), expectedValues.length == childExpressions.length); for (int i = 0; i < childDmcsAccessor.length; i++) { assertTrue("Expected: " + expectedValues[i] + " got: " + childDmcsAccessor[i].getRelativeExpression(), childDmcsAccessor[i].getRelativeExpression().equals(expectedValues[i])); } return childDmcs; } /** * This test verifies that large arrays are properly partitioned and * the handling of "small" arrays is not affected. */ @Test public void testArrays() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testArrays"); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // int array_simple[10]; IExpressionDMContext arraySimpleExprDMC = SyncUtil.createExpression(frameDmc, "array_simple"); assertChildrenCount(arraySimpleExprDMC, 10); // get all children String[] expectedValues = new String[10]; for (int i = 0; i < expectedValues.length; ++i) { expectedValues[i] = String.format("array_simple[%d]", i); } IExpressionDMContext[] arraySimpleChildren = getChildren(arraySimpleExprDMC, expectedValues); for (IExpressionDMContext ctx : arraySimpleChildren) getChildren(ctx, new String[0]); // get some parts of the children array getChildren(arraySimpleExprDMC, 3, 2, new String[] { "array_simple[3]", "array_simple[4]" }); getChildren(arraySimpleExprDMC, 9, 3, new String[] { "array_simple[9]" }); // int array_int[24321]; IExpressionDMContext arrayIntExprDMC = SyncUtil.createExpression(frameDmc, "array_int"); assertChildrenCount(arrayIntExprDMC, 3); // get top level partitions: [0-9999], [10000-19999], [20000-24321] IExpressionDMContext[] arrayIntPartitions = getChildren(arrayIntExprDMC, new String[] {"*((array_int)+0)@10000", "*((array_int)+10000)@10000", "*((array_int)+20000)@4321"}); assertTrue(String.format("Invalid number of partition: expected 3 got %d", arrayIntPartitions.length), arrayIntPartitions.length == 3); // get children of the last partition: [20000-24321] expectedValues = new String[44]; for(int i = 0; i < expectedValues.length - 1; ++i) { expectedValues[i] = String.format("*((array_int)+%d)@100", 20000 + i*100); } expectedValues[expectedValues.length - 1] = "*((array_int)+24300)@21"; IExpressionDMContext[] arrayIntPartitions1 = getChildren(arrayIntPartitions[2], expectedValues); expectedValues = new String[21]; for(int i = 0; i < expectedValues.length; ++i) { expectedValues[i] = String.format("array_int[%d]", 24300 + i); } getChildren(arrayIntPartitions1[arrayIntPartitions1.length - 1], expectedValues); // foo array_foo[1200]; IExpressionDMContext arrayFooExprDMC = SyncUtil.createExpression(frameDmc, "array_foo"); assertChildrenCount(arrayFooExprDMC, 12); expectedValues = new String[12]; for (int i = 0; i < expectedValues.length; ++i) { expectedValues[i] = String.format("*((array_foo)+%d)@%d", i*100, 100); } IExpressionDMContext[] arrayFooPartitions = getChildren(arrayFooExprDMC, expectedValues); for (int i = 0; i < arrayFooPartitions.length; ++i) { IExpressionDMContext ctx = arrayFooPartitions[i]; assertTrue(String.format("Invalid DM context type: expected '%s' got '%s'", IIndexedPartitionDMContext.class.getName(), ctx.getClass().getName()), ctx instanceof IIndexedPartitionDMContext); expectedValues = new String[100]; for (int j = 0; j < expectedValues.length; ++j) { expectedValues[j] = String.format("array_foo[%d]", i*100 + j); } IExpressionDMContext[] arrayFooChildren = getChildren(ctx, expectedValues); // check the children of a couple of children getChildren(arrayFooChildren[0], new String[] {"bar", "bar2", "a", "b", "c"}); getChildren(arrayFooChildren[80], new String[] {"bar", "bar2", "a", "b", "c"}); // get parts of the children array expectedValues = new String[] { String.format("array_foo[%d]", i*100 + 3), String.format("array_foo[%d]", i*100 + 4) }; getChildren(ctx, 3, 2, expectedValues); getChildren(ctx, 99, 3, new String[] { String.format("array_foo[%d]", i*100 + 99) }); } } /** * This test verifies that large double arrays are properly partitioned */ @Test public void testLargeDoubleArray() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testArrays"); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // char array_double_large[111][210] IExpressionDMContext arrayDoubleLargeExprDMC = SyncUtil.createExpression(frameDmc, "array_double_large"); assertChildrenCount(arrayDoubleLargeExprDMC, 2); // get top level partitions: [0-99], [100-110] IExpressionDMContext[] arrayTopPartitions = getChildren(arrayDoubleLargeExprDMC, new String[] {"*((array_double_large)+0)@100", "*((array_double_large)+100)@11"}); assertTrue(String.format("Invalid number of partition: expected 2 got %d", arrayTopPartitions.length), arrayTopPartitions.length == 2); // get children child array_double_large[100-110] IExpressionDMContext arrayDoubleLargeChildExprDMC = arrayTopPartitions[1]; assertChildrenCount(arrayDoubleLargeChildExprDMC, 11); String[] expectedValues = new String[11]; for(int i = 0; i < expectedValues.length; ++i) { expectedValues[i] = String.format("array_double_large[%d]", 100 +i); } IExpressionDMContext[] arrayChild = getChildren(arrayDoubleLargeChildExprDMC, expectedValues); // get second level partitions: array_double_large[101][0-99], [100-199], [200-209] IExpressionDMContext arrayDoubleLargeChildExprDMC2 = arrayChild[1]; assertChildrenCount(arrayDoubleLargeChildExprDMC2, 3); IExpressionDMContext[] arraySecondLevelPartitions = getChildren(arrayDoubleLargeChildExprDMC2, new String[] {"*((array_double_large[101])+0)@100", "*((array_double_large[101])+100)@100", "*((array_double_large[101])+200)@10"}); assertTrue(String.format("Invalid number of partition: expected 3 got %d", arraySecondLevelPartitions.length), arraySecondLevelPartitions.length == 3); // get children of array_double_large[101][0-99] IExpressionDMContext arrayDoubleLargeChildExprDMC3 = arraySecondLevelPartitions[0]; assertChildrenCount(arrayDoubleLargeChildExprDMC3, 100); expectedValues = new String[100]; for(int i = 0; i < expectedValues.length; ++i) { expectedValues[i] = String.format("array_double_large[101][%d]", i); } IExpressionDMContext[] arrayChild2 = getChildren(arrayDoubleLargeChildExprDMC3, expectedValues); // No more children for array_double_large[101][*] for (IExpressionDMContext ctx : arrayChild2) getChildren(ctx, new String[0]); // get some parts of the children array getChildren(arrayDoubleLargeChildExprDMC3, 3, 2, new String[] { "array_double_large[101][3]", "array_double_large[101][4]" }); getChildren(arrayDoubleLargeChildExprDMC3, 98, 3, new String[] { "array_double_large[101][98]","array_double_large[101][99]" }); } /** * This test verifies that "small" double arrays is not affected by partitions. */ @Test public void testSmallDoubleArray() throws Throwable { MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testArrays"); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // int array_double_small[11][21]; IExpressionDMContext arrayDoubleSmallExprDMC = SyncUtil.createExpression(frameDmc, "array_double_small"); assertChildrenCount(arrayDoubleSmallExprDMC, 11); // get all children of array_double_small String[] expectedValues = new String[11]; for (int i = 0; i < expectedValues.length; ++i) { expectedValues[i] = String.format("array_double_small[%d]", i); } IExpressionDMContext[] arrayDoubleSmallChildren = getChildren(arrayDoubleSmallExprDMC, expectedValues); // get all children of array_double_small[3] IExpressionDMContext arrayDoubleSmallChildExprDMC = arrayDoubleSmallChildren[3]; assertChildrenCount(arrayDoubleSmallChildExprDMC, 21); expectedValues = new String[21]; for (int i = 0; i < expectedValues.length; ++i) { expectedValues[i] = arrayDoubleSmallChildExprDMC.getExpression() + "[" + i +"]"; } IExpressionDMContext[] arrayDoubleSmallGrandChildren = getChildren(arrayDoubleSmallChildExprDMC, expectedValues); // No more children for array_double_small[3][*] for (IExpressionDMContext ctx : arrayDoubleSmallGrandChildren) getChildren(ctx, new String[0]); // get some parts of the children array getChildren(arrayDoubleSmallChildExprDMC, 3, 2, new String[] { "array_double_small[3][3]", "array_double_small[3][4]" }); getChildren(arrayDoubleSmallChildExprDMC, 19, 3, new String[] { "array_double_small[3][19]","array_double_small[3][20]" }); } /** * This test verifies that there is no RTTI support before GDB 7.5. */ @Test public void testRTTI() throws Throwable { assumeGdbVersionNot(ITestConstants.SUFFIX_GDB_6_7); // crashing assumeGdbVersionLowerThen(ITestConstants.SUFFIX_GDB_7_5); SyncUtil.runToLocation("testRTTI"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // The expression we will follow as it changes types: derived.ptr IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "derived.ptr"); // Now, the expression should be type VirtualBase getExpressionType(exprDmc, "VirtualBase *"); assertChildrenCount(exprDmc, 2); // get all children String[] expectedValues = new String[2]; expectedValues[0] = "a"; expectedValues[1] = "b"; getChildren(exprDmc, expectedValues); // Make the type of our expression change SyncUtil.step(1, StepType.STEP_OVER); // Now, the expression should be type Derived, but GDB < 7.5 does not tell us // so we should still get the base type. getExpressionType(exprDmc, "VirtualBase *"); assertChildrenCount(exprDmc, 2); // The children are also the same as before getChildren(exprDmc, expectedValues); // Make the type of our expression change SyncUtil.step(1, StepType.STEP_OVER); // Now, the expression should be type OtherDerived, but GDB < 7.5 does not tell us // so we should still get the base type. getExpressionType(exprDmc, "VirtualBase *"); assertChildrenCount(exprDmc, 2); // The children are also the same as before getChildren(exprDmc, expectedValues); } /** * This test verifies that we can cast to a type and then revert. */ @Test public void testCastToType() throws Throwable { SyncUtil.runToLocation("testCasting"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "int_ptr"); assertTrue("Expression service does not support casting", fExpService instanceof IExpressions2); ICastedExpressionDMContext castExprDmc = ((IExpressions2)fExpService).createCastedExpression(exprDmc, new CastInfo("char*")); // Check type of original expression and new casted one getExpressionType(exprDmc, "int *"); getExpressionType(castExprDmc, "char *"); assertChildrenCount(castExprDmc, 1); // get child and its value final IExpressionDMContext[] children = getChildren(exprDmc, new String[] {"*int_ptr"}); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(children[0], IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("65", value); final IExpressionDMContext[] castChildren = getChildren(castExprDmc, new String[] {"*((char*)(int_ptr))"}); query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(castChildren[0], IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("65 'A'", value); // Now check that the casted type still remembers what its original type is assertEquals(castExprDmc.getParents()[0], exprDmc); } /** * This test verifies that we can display as array and then revert. */ @Test public void testDisplayAsArray() throws Throwable { SyncUtil.runToLocation("testCasting"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "int_ptr"); assertTrue("Expression service does not support casting", fExpService instanceof IExpressions2); // Display as an array of 2 elements, starting at index 1 ICastedExpressionDMContext castExprDmc = ((IExpressions2)fExpService).createCastedExpression(exprDmc, new CastInfo(1,2)); // Check type of original expression and new casted one getExpressionType(exprDmc, "int *"); getExpressionType(castExprDmc, "int [2]"); assertChildrenCount(castExprDmc, 2); // get children and their values final IExpressionDMContext[] children = getChildren(castExprDmc, new String[] {"int_ptr[1]", "int_ptr[2]"}); String[] expectedValues = new String[] {"1094861636", "1162233672"}; for (int i = 0; i<children.length;i++) { final IExpressionDMContext child = children[i]; Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals(expectedValues[i], value); } // Now check that the casted type still remembers what its original type is assertEquals(castExprDmc.getParents()[0], exprDmc); } /** * This test verifies that we can display as array and cast to a type together * and then revert. */ @Test public void testDisplayAsArrayAndCastToType() throws Throwable { SyncUtil.runToLocation("testCasting"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "int_ptr"); assertTrue("Expression service does not support casting", fExpService instanceof IExpressions2); // We create the casted type and the displaying as an array in a single request. This is because // that is the way the UI does it. Furthermore, the service handles the cast first, then the // array, which is why our array of 2 ints becomes 8 chars, and then we only look at 4 of them // starting at index 4. ICastedExpressionDMContext castExprDmc = ((IExpressions2)fExpService).createCastedExpression(exprDmc, new CastInfo("char*", 4,4)); getExpressionType(castExprDmc, "char [4]"); assertChildrenCount(castExprDmc, 4); // get children and their values // The array index starts at 0 again because the cast to char[] creates a new array final IExpressionDMContext[] children = getChildren(castExprDmc, new String[] {"int_ptr[4]", "int_ptr[5]", "int_ptr[6]", "int_ptr[7]"}); String[] expectedValues = new String[] { "68 'D'", "67 'C'", "66 'B'", "65 'A'"}; for (int i = 0; i<children.length;i++) { final IExpressionDMContext child = children[i]; getExpressionType(child, "char"); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals(expectedValues[i], value); } // Now check that the casted type still remembers what its original type is assertEquals(castExprDmc.getParents()[0], exprDmc); } /** * This test verifies that we can cast an array to a different type and then revert. */ @Test public void testCastToTypeOfArray() throws Throwable { SyncUtil.runToLocation("testCasting"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "array_small"); assertTrue("Expression service does not support casting", fExpService instanceof IExpressions2); ICastedExpressionDMContext castExprDmc = ((IExpressions2)fExpService).createCastedExpression(exprDmc, new CastInfo("char[]")); getExpressionType(exprDmc, "int [4]"); getExpressionType(castExprDmc, "char [16]"); assertChildrenCount(castExprDmc, 16); // get children and their values // The array index starts at 0 again because the cast to char[] creates a new array final IExpressionDMContext[] children = getChildren(castExprDmc, new String[] {"array_small[0]", "array_small[1]", "array_small[2]", "array_small[3]", "array_small[4]", "array_small[5]", "array_small[6]", "array_small[7]", "array_small[8]", "array_small[9]", "array_small[10]", "array_small[11]", "array_small[12]", "array_small[13]", "array_small[14]", "array_small[15]"}); // Only check elements 4 through 7 for simplicity String[] expectedValues = new String[] { "68 'D'", "67 'C'", "66 'B'", "65 'A'"}; for (int i = 4; i<8;i++) { final IExpressionDMContext child = children[i]; getExpressionType(child, "char"); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals(expectedValues[i-4], value); } // Now check that the casted type still remembers what its original type is assertEquals(castExprDmc.getParents()[0], exprDmc); } /** * This test verifies that we can cast to a type and then revert * when dealing with an array with partitions. */ @Test public void testCastToTypeWithPartition() throws Throwable { SyncUtil.runToLocation("testCasting"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "array_large"); assertTrue("Expression service does not support casting", fExpService instanceof IExpressions2); ICastedExpressionDMContext castExprDmc = ((IExpressions2)fExpService).createCastedExpression(exprDmc, new CastInfo("char[]")); // Check type of original expression and new casted one getExpressionType(exprDmc, "int [111]"); getExpressionType(castExprDmc, "char [444]"); // get the 5 partition children assertChildrenCount(castExprDmc, 5); IExpressionDMContext[] children = getChildren(castExprDmc, new String[] {"*((((char[])(array_large)))+0)@100", "*((((char[])(array_large)))+100)@100", "*((((char[])(array_large)))+200)@100", "*((((char[])(array_large)))+300)@100", "*((((char[])(array_large)))+400)@44" }); // Now make sure the children of the partitions have the proper casting final String[] expectedChildren = new String[100]; for (int i=0; i < expectedChildren.length; i++) { expectedChildren[i] = String.format("array_large[%d]", i); } IExpressionDMContext[] castedChildren = getChildren(children[0], expectedChildren); assertEquals(100, castedChildren.length); // Check the type and value of a few of the first children final String[] expectedValues = new String[] { "65 'A'", "0 '\\0'", "0 '\\0'", "0 '\\0'", "68 'D'", "67 'C'", "66 'B'", "65 'A'" }; for (int i = 0; i < expectedValues.length; i++) { final IExpressionDMContext child = castedChildren[i]; getExpressionType(child, "char"); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals(expectedValues[i], value); } // Now check that the casted type still remembers what its original type is assertEquals(castExprDmc.getParents()[0], exprDmc); } /** * This test verifies that we can display as array and then revert * when dealing with an array with partitions. */ @Test public void testDisplayAsArrayWithPartition() throws Throwable { SyncUtil.runToLocation("testCasting"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // The expression we will cast from int to char IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "array_large"); assertTrue("Expression service does not support casting", fExpService instanceof IExpressions2); // Display as an array of 101 elements, starting at index 1 (we need at least 101 elements to get partitions) ICastedExpressionDMContext castExprDmc = ((IExpressions2)fExpService).createCastedExpression(exprDmc, new CastInfo(1, 101)); // Check type of original expression and new casted one getExpressionType(exprDmc, "int [111]"); getExpressionType(castExprDmc, "int [101]"); // Two partitions as children assertChildrenCount(castExprDmc, 2); IExpressionDMContext[] children = getChildren(castExprDmc, new String[] {"*(((*((array_large)+1)@101))+0)@100", "*(((*((array_large)+1)@101))+100)@1" }); assertTrue("Should have seen the child as a partition", children[0] instanceof IIndexedPartitionDMContext); assertEquals("Wrong start index for partition", 0, ((IIndexedPartitionDMContext)children[0]).getIndex()); assertEquals("Wrong partition length", 100, ((IIndexedPartitionDMContext)children[0]).getLength()); assertTrue("Should have seen the child as a partition", children[1] instanceof IIndexedPartitionDMContext); assertEquals("Wrong start index for partition", 100, ((IIndexedPartitionDMContext)children[1]).getIndex()); assertEquals("Wrong partition length", 1, ((IIndexedPartitionDMContext)children[1]).getLength()); // Now make sure the children of the partitions have the proper casting and start at the proper index final String[] expectedChildren = new String[100]; for (int i=0; i < expectedChildren.length; i++) { expectedChildren[i] = String.format("array_large[%d]", i+1); } IExpressionDMContext[] castedChildren = getChildren(children[0], expectedChildren); assertEquals(100, castedChildren.length); // Check the type and value of a few of the first children final String[] expectedValues = new String[] { "1094861636", "1162233672" }; for (int i = 0; i < expectedValues.length; i++) { final IExpressionDMContext child = castedChildren[i]; getExpressionType(child, "int"); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals(expectedValues[i], value); } // Now check that the casted type still remembers what its original type is assertEquals(castExprDmc.getParents()[0], exprDmc); } /** * This test verifies that we can display as array and cast to a type together * and then revert when dealing with an array with partitions. */ @Test public void testDisplayAsArrayAndCastToTypeWithPartition() throws Throwable { SyncUtil.runToLocation("testCasting"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "array_large"); assertTrue("Expression service does not support casting", fExpService instanceof IExpressions2); ICastedExpressionDMContext castExprDmc = ((IExpressions2)fExpService).createCastedExpression(exprDmc, new CastInfo("char[]", 4, 101)); // Check type of original expression and new casted one getExpressionType(exprDmc, "int [111]"); getExpressionType(castExprDmc, "char [101]"); // get the 5 partition children assertChildrenCount(castExprDmc, 2); IExpressionDMContext[] children = getChildren(castExprDmc, new String[] {"*(((*(((char[])(array_large))+4)@101))+0)@100", "*(((*(((char[])(array_large))+4)@101))+100)@1"}); assertTrue("Should have seen the child as a partition", children[0] instanceof IIndexedPartitionDMContext); assertEquals("Wrong start index for partition", 0, ((IIndexedPartitionDMContext)children[0]).getIndex()); assertEquals("Wrong partition length", 100, ((IIndexedPartitionDMContext)children[0]).getLength()); assertTrue("Should have seen the child as a partition", children[1] instanceof IIndexedPartitionDMContext); assertEquals("Wrong start index for partition", 100, ((IIndexedPartitionDMContext)children[1]).getIndex()); assertEquals("Wrong partition length", 1, ((IIndexedPartitionDMContext)children[1]).getLength()); // Now make sure the children of the partitions have the proper casting final String[] expectedChildren = new String[100]; for (int i=0; i < expectedChildren.length; i++) { expectedChildren[i] = String.format("array_large[%d]", i+4); } IExpressionDMContext[] castedChildren = getChildren(children[0], expectedChildren); assertEquals(100, castedChildren.length); // Check the type and value of a few of the first children final String[] expectedValues = new String[] { "68 'D'", "67 'C'", "66 'B'", "65 'A'" }; for (int i = 0; i < expectedValues.length; i++) { final IExpressionDMContext child = castedChildren[i]; getExpressionType(child, "char"); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals(expectedValues[i], value); } // Now check that the casted type still remembers what its original type is assertEquals(castExprDmc.getParents()[0], exprDmc); } /** * This test verifies that we display the simple return value of a method after * a step-return operation, but only for the first stack frame. */ @Test public void testDisplaySimpleReturnValueForStepReturn() throws Throwable { SyncUtil.runToLocation("testSimpleReturn"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_RETURN); // Check the return value is shown when looking at the first frame final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IVariableDMData[] result = SyncUtil.getLocals(frameDmc); assertEquals(3, result.length); // Two variables and one return value // Return value assertEquals("$2", result[0].getName()); assertEquals("6", result[0].getValue()); // first variable assertEquals("a", result[1].getName()); assertEquals("10", result[1].getValue()); // Second variable assertEquals("b", result[2].getName()); assertEquals("false", result[2].getValue()); // Now check how the return value will be displayed to the user final IExpressionDMContext returnExprDmc = SyncUtil.createExpression(frameDmc, "$2"); Query<IExpressionDMData> query = new Query<IExpressionDMData>() { @Override protected void execute(final DataRequestMonitor<IExpressionDMData> rm) { fExpService.getExpressionData(returnExprDmc, rm); } }; fSession.getExecutor().execute(query); IExpressionDMData data = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("testSimpleReturn() returned", data.getName()); // Now check the actual value using the expression service String value = SyncUtil.getExpressionValue(returnExprDmc, IFormattedValues.DECIMAL_FORMAT); assertEquals("6", value); // Now make sure we don't show the return value for another frame final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1); result = SyncUtil.getLocals(frameDmc2); // only one variable assertEquals(1, result.length); assertEquals("b", result[0].getName()); } /** * This test verifies that we display the complex return value of a method after * a step-return operation, but only for the first stack frame. */ @Test public void testDisplayComplexReturnValueForStepReturn() throws Throwable { SyncUtil.runToLocation("testComplexReturn"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_RETURN); // Check the return value is show when looking at the first frame final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IVariableDMData[] result = SyncUtil.getLocals(frameDmc); assertEquals(3, result.length); // Two variables and one return value // Return value assertEquals("$2", result[0].getName()); // first variable assertEquals("a", result[1].getName()); assertEquals("10", result[1].getValue()); // Second variable assertEquals("b", result[2].getName()); assertEquals("false", result[2].getValue()); // Now check how the return value will be displayed to the user final IExpressionDMContext returnExprDmc = SyncUtil.createExpression(frameDmc, "$2"); Query<IExpressionDMData> query = new Query<IExpressionDMData>() { @Override protected void execute(final DataRequestMonitor<IExpressionDMData> rm) { fExpService.getExpressionData(returnExprDmc, rm); } }; fSession.getExecutor().execute(query); IExpressionDMData data = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("testComplexReturn() returned", data.getName()); // Now check the content of the complex return expression doTestChildren(returnExprDmc); // Now make sure we don't show the return value for another frame IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1); result = SyncUtil.getLocals(frameDmc2); // only one variable assertEquals(1, result.length); assertEquals("b", result[0].getName()); } /** * This test verifies that we properly display variables after a step-return operation * from a method returning void. */ @Test public void testNoReturnValueForEmptyStepReturn() throws Throwable { SyncUtil.runToLocation("noReturnValue"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_RETURN); // Check no return value is shown when looking at the first frame final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IVariableDMData[] result = SyncUtil.getLocals(frameDmc); assertEquals(2, result.length); // Two variables and one return value // first variable assertEquals("a", result[0].getName()); assertEquals("10", result[0].getValue()); // Second variable assertEquals("b", result[1].getName()); assertEquals("false", result[1].getValue()); } /** * This tests verifies that we can obtain a child even though * is was already created directly. */ @Test public void testExistingChild() throws Throwable { SyncUtil.runToLocation("testExistingChild"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final String PARENT_EXPR = "b"; final String CHILD_EXPR = "((b).d)"; final String CHILD__REL_EXPR = "d"; // Fetch the child directly final IExpressionDMContext childDmc = SyncUtil.createExpression(frameDmc, CHILD_EXPR); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(childDmc, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleSuccess() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("8", value); // Now fetch the child through its parent final IExpressionDMContext parentDmc = SyncUtil.createExpression(frameDmc, PARENT_EXPR); query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getSubExpressions( parentDmc, new ImmediateDataRequestMonitor<IExpressionDMContext[]>(rm) { @Override protected void handleSuccess() { if (getData().length != 2) { rm.done(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Wrong number for children. Expecting 2 but got " + getData().length, null)); return; } MIExpressionDMC firstChildContext = (MIExpressionDMC)getData()[0]; if (firstChildContext.getExpression().equals(CHILD_EXPR) == false) { rm.done(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got wrong first child. Expected " + CHILD_EXPR + " but got " + firstChildContext.getExpression(), null)); return; } if (firstChildContext.getRelativeExpression().equals(CHILD__REL_EXPR) == false) { rm.done(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got wrong relative expression. Expected " + CHILD__REL_EXPR + " but got " + firstChildContext.getRelativeExpression(), null)); return; } fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(firstChildContext, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleSuccess() { rm.done(getData().getFormattedValue()); } }); } }); } }; fSession.getExecutor().execute(query); value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("8", value); } /** * This tests verifies that we can manually create a child of an expression * after that child was automatically created through the parent. * This case happens when selecting a child of an expression and using "Watch" * to create an expression automatically. */ @Test public void testExplicitChildCreation() throws Throwable { SyncUtil.runToLocation("testExistingChild"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final String PARENT_EXPR = "b"; final String CHILD_EXPR = "((b).d)"; final String CHILD__REL_EXPR = "d"; // First fetch the child through its parent final IExpressionDMContext parentDmc = SyncUtil.createExpression(frameDmc, PARENT_EXPR); Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getSubExpressions( parentDmc, new ImmediateDataRequestMonitor<IExpressionDMContext[]>(rm) { @Override protected void handleSuccess() { if (getData().length != 2) { rm.done(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Wrong number for children. Expecting 2 but got " + getData().length, null)); return; } MIExpressionDMC firstChildContext = (MIExpressionDMC)getData()[0]; if (firstChildContext.getExpression().equals(CHILD_EXPR) == false) { rm.done(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got wrong first child. Expected " + CHILD_EXPR + " but got " + firstChildContext.getExpression(), null)); return; } if (firstChildContext.getRelativeExpression().equals(CHILD__REL_EXPR) == false) { rm.done(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got wrong relative expression. Expected " + CHILD__REL_EXPR + " but got " + firstChildContext.getRelativeExpression(), null)); return; } fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(firstChildContext, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleSuccess() { rm.done(getData().getFormattedValue()); } }); } }); } }; fSession.getExecutor().execute(query); String value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("8", value); // Now access the child directly final IExpressionDMContext childDmc = SyncUtil.createExpression(frameDmc, CHILD_EXPR); query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getFormattedExpressionValue( fExpService.getFormattedValueContext(childDmc, IFormattedValues.NATURAL_FORMAT), new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleSuccess() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals("8", value); } protected void assertChildrenCount(final IExpressionDMContext parentDmc, final int expectedCount) throws Throwable { Query<Integer> query = new Query<Integer>() { @Override protected void execute(DataRequestMonitor<Integer> rm) { fExpService.getSubExpressionCount(parentDmc, rm); } }; fExpService.getExecutor().submit(query); int count = query.get().intValue(); assertThat(count, is(expectedCount)); } protected String getExpressionType(final IExpressionDMContext exprDmc, final String expectedType) throws Throwable { Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fExpService.getExpressionData( exprDmc, new ImmediateDataRequestMonitor<IExpressionDMData>(rm) { @Override protected void handleCompleted() { rm.done(getData().getTypeName()); } }); } }; fSession.getExecutor().execute(query); String type = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); assertEquals(expectedType, type); return type; } // Slight change in GDB output to fix a bug, so we must change the test a // little // Bug 320277 @Test public void testDeleteChildren_7_3() throws Throwable { assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_7_3); SyncUtil.runToLocation("testDeleteChildren"); MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER); final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // First create the var object and all its children IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "f"); fExpService.getSubExpressions(parentDmc, new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().length != 5) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 5 got " + getData().length, null)); } else { String childStr = "((class bar) f)"; if (!getData()[0].getExpression().equals(childStr)) { wait.waitFinished(new Status( IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got child " + getData()[0].getExpression() + " instead of " + childStr, null)); } else { // Now list the children of the // first element fExpService.getSubExpressions(getData()[0], new DataRequestMonitor<IExpressionDMContext[]>( fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { if (getData().length != 2) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Failed getting children; expecting 2 got " + getData().length, null)); } else { String childStr = "((((class bar) f)).d)"; if (!getData()[0].getExpression() .equals(childStr)) { wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Got child " + getData()[0].getExpression() + " instead of " + childStr, null)); } else { wait.setReturnInfo(getData()[0]); wait.waitFinished(); } } } } }); } } } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); final IExpressionDMContext deletedChildDmc = (IExpressionDMContext) wait.getReturnInfo(); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // Now create more than 1000 expressions to trigger the deletion // of the children // that were created above for (int i = 0; i < 1100; i++) { IExpressionDMContext dmc = fExpService.createExpression(frameDmc, "a[" + i + "]"); wait.increment(); fExpService.getExpressionData(dmc, new DataRequestMonitor<IExpressionDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { wait.waitFinished(); } } }); } } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); fExpService.getExecutor().submit(new Runnable() { @Override public void run() { // Evaluate the expression of a child that we know is deleted to // make sure // the expression service can handle that fExpService.getExpressionData(deletedChildDmc, new DataRequestMonitor<IExpressionDMData>(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { if (!isSuccess()) { wait.waitFinished(getStatus()); } else { wait.waitFinished(); } } }); } }); wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(wait.getMessage(), wait.isOK()); wait.waitReset(); } /** * This test verifies that there is proper RTTI support starting with GDB * 7.5. */ @Test public void testRTTI_7_5() throws Throwable { assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_7_5); SyncUtil.runToLocation("testRTTI"); MIStoppedEvent stoppedEvent = SyncUtil.step(3, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // The expression we will follow as it changes types: derived.ptr IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "derived.ptr"); // Now, the expression should be type VirtualBase getExpressionType(exprDmc, "VirtualBase *"); assertChildrenCount(exprDmc, 2); // get all children String[] expectedValues = new String[2]; expectedValues[0] = "a"; expectedValues[1] = "b"; getChildren(exprDmc, expectedValues); // Make the type of our expression change SyncUtil.step(1, StepType.STEP_OVER); // Now, the expression should be type Derived getExpressionType(exprDmc, "Derived *"); assertChildrenCount(exprDmc, 5); // get all children expectedValues = new String[5]; expectedValues[0] = "VirtualBase"; expectedValues[1] = "c"; expectedValues[2] = "ptr"; expectedValues[3] = "d"; expectedValues[4] = "e"; getChildren(exprDmc, expectedValues); // Make the type of our expression change SyncUtil.step(1, StepType.STEP_OVER); // Now, the expression should be type OtherDerived getExpressionType(exprDmc, "OtherDerived *"); assertChildrenCount(exprDmc, 4); // get all children expectedValues = new String[4]; expectedValues[0] = "VirtualBase"; expectedValues[1] = "d"; expectedValues[2] = "c"; expectedValues[3] = "f"; getChildren(exprDmc, expectedValues); } }