| /******************************************************************************* |
| * 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); |
| } |
| |
| } |