/******************************************************************************* * Copyright (c) 2012, 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: * Marc Khouzam (Ericsson) - Initial Implementation * Marc Khouzam (Ericsson) - Tests for Pattern Matching for variables (Bug 394408) * Alvaro Sanchez-Leon (Ericsson AB) - Allow user to edit register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.tests.dsf.gdb.tests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; 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.datamodel.DMContexts; import org.eclipse.cdt.dsf.debug.service.IExpressions; 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.IExpressionDMLocation; 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.IRegisters.IRegisterDMContext; import org.eclipse.cdt.dsf.debug.service.IRegisters2; import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.mi.service.ClassAccessor.MIExpressionDMCAccessor; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExpressions; import org.eclipse.cdt.dsf.mi.service.MIRegisters.MIRegisterDMC; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil; import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase { private static final String EXEC_NAME = "PatternMatchingExpressionsTestApp.exe"; private DsfSession fSession; private DsfServicesTracker fServicesTracker; protected IMIExpressions fExpService; protected IRegisters2 fRegService; @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(IMIExpressions.class); fRegService = fServicesTracker.getService(IRegisters2.class); } }; fSession.getExecutor().submit(runnable).get(); } @Override public void doAfterTest() throws Exception { super.doAfterTest(); fExpService = null; if (fServicesTracker != null) { fServicesTracker.dispose(); fServicesTracker = null; } } //************************************************************************************** // Utility methods //************************************************************************************** // Static list of register names as obtained directly from GDB. // We make it static so it does not get re-set for every test protected static List<String> fRegisterNames = null; @BeforeClass public static void initializeGlobals() { // In case we run multiple GDB versions of this test // in the same suite, we need to re-initialize the registers // as they may change between GDB versions. fRegisterNames = null; } protected List<String> get_X86_REGS() throws Throwable { if (fRegisterNames == null) { // The tests must run on different machines, so the set of registers can change. // To deal with this we ask GDB for the list of registers. // Note that we send an MI Command in this code and do not use the IRegister service; // this is because we want to test the service later, comparing it to what we find // by asking GDB directly. final IContainerDMContext container = SyncUtil.getContainerContext(); Query<MIDataListRegisterNamesInfo> query = new Query<MIDataListRegisterNamesInfo>() { @Override protected void execute(DataRequestMonitor<MIDataListRegisterNamesInfo> rm) { IMICommandControl controlService = fServicesTracker.getService(IMICommandControl.class); controlService.queueCommand( controlService.getCommandFactory().createMIDataListRegisterNames(container), rm); } }; fSession.getExecutor().execute(query); MIDataListRegisterNamesInfo data = query.get(); String[] names = data.getRegisterNames(); // Remove registers with empty names since the service also // remove them. I don't know why GDB returns such empty names. fRegisterNames = new LinkedList<String>(); for (String name : names) { if (!name.isEmpty()) { // Add the '$' prefix fRegisterNames.add("$"+name); } } } // Return a copy since it will be modified by each test return new LinkedList<String>(fRegisterNames); } final static String[] fAllVariables = new String[] { "firstarg", "firstvar", "ptrvar", "secondarg", "secondvar", "var", "var2" }; protected void checkChildrenCount(final IExpressionDMContext parentDmc, final int expectedCount) throws Throwable { Query<Integer> query = new Query<Integer>() { @Override protected void execute(final DataRequestMonitor<Integer> rm) { fExpService.getSubExpressionCount(parentDmc, rm); } }; fSession.getExecutor().execute(query); int count = query.get(); assertTrue(String.format("Expected %d but got %d", expectedCount, count), count == expectedCount); } protected String getRegisterValue(final String regName, final IMIExecutionDMContext threadDmc) throws Exception { Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { fRegService.getRegisters(threadDmc, new ImmediateDataRequestMonitor<IRegisterDMContext[]>(rm) { @Override protected void handleSuccess() { assert getData() instanceof MIRegisterDMC[]; for (MIRegisterDMC register : (MIRegisterDMC[])getData()) { if (register.getName().equals(regName)) { final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(register, IFormattedValues.HEX_FORMAT); fRegService.getFormattedExpressionValue(valueDmc, new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleSuccess() { rm.done(getData().getFormattedValue()); }; }); return; } } // If we get here, we didn't find the register! assertTrue("Invalid register: " + regName, false); } }); } }; fSession.getExecutor().execute(query); return query.get(); } protected String getExpressionValue(final IExpressionDMContext exprDmc) throws Throwable { Query<String> query = new Query<String>() { @Override protected void execute(final DataRequestMonitor<String> rm) { final FormattedValueDMContext valueDmc = fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT); fExpService.getFormattedExpressionValue(valueDmc, new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) { @Override protected void handleSuccess() { rm.done(getData().getFormattedValue()); } }); } }; fSession.getExecutor().execute(query); return query.get(); } // This method tests IExpressions.getSubExpressions(IExpressionDMC, int, int, DRM); protected IExpressionDMContext[] checkChildren(final IExpressionDMContext parentDmc, final int startIndex, final int length, String[] expectedValues) throws Throwable { Query<IExpressionDMContext[]> query = new Query<IExpressionDMContext[]>() { @Override protected void execute(final DataRequestMonitor<IExpressionDMContext[]> rm) { fExpService.getSubExpressions(parentDmc, startIndex, length, rm); } }; fSession.getExecutor().execute(query); IExpressionDMContext[] childDmcs = query.get(); 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(childDmcsAccessor[i].getRelativeExpression(), expectedValues[i]); } return childDmcs; } //************************************************************************************** // Tests methods //************************************************************************************** /** * Test that we can access a single register, without using groups or patterns */ @Test public void testSingleReg() throws Throwable { final String regName = "cs"; final String exprString = "$" + regName; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); // get value of expression and compare with register assertEquals(getRegisterValue(regName, threadDmc), getExpressionValue(exprDmc)); } /** * Test that we can access a single variable, without using groups or patterns */ @Test public void testSingleLocal() throws Throwable { final String exprString = "secondvar"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); assertEquals(getExpressionValue(exprDmc), "0x12"); } /** * Test that we can match a single register */ @Test public void testMatchSingleReg() throws Throwable { final String exprString = "=$xmm0"; final String[] children = new String[] { "$xmm0" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match a single variable */ @Test public void testMatchSingleLocal() throws Throwable { final String exprString = "=secondvar"; final String[] children = new String[] { "secondvar" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can create the all-register match and that * the '$*' form is treated just like '=$*' */ @Test public void testMatchAllRegs() throws Throwable { final String exprString = "$*"; final String exprString2 = "=$*"; List<String> regList = get_X86_REGS(); Collections.sort(regList); final String[] children = regList.toArray(new String[0]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); exprDmc = SyncUtil.createExpression(frameDmc, exprString2); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can create the all-locals match and that * the '*' form is treated just like '=*' */ @Test public void testMatchAllLocals() throws Throwable { final String exprString = "*"; final String exprString2 = "=*"; final String[] children = fAllVariables; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); exprDmc = SyncUtil.createExpression(frameDmc, exprString2); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can create the all-locals match for another frame */ @Test public void testMatchAllLocalsOtherFrame() throws Throwable { final String exprString = "*"; final String[] children = new String[] { "argc", "argv", "boolvar", "chararray", "intvar" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that registers can be matched using '*' */ @Test public void testMatchRegWithStar() throws Throwable { final String exprString = "=$f*"; final String[] children = new String[] { "$fctrl", "$fioff", "$fiseg", "$fooff", "$fop", "$foseg", "$fs", "$fstat", "$ftag" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that registers can be multiplied using '*' * without conflicting with glob-expressions */ @Test public void testMultiplyReg() throws Throwable { final String exprString = "$fctrl*0"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); assertEquals(getExpressionValue(exprDmc), "0x0"); } /** * Test that variables can be matched using '*' at the start * not to be confused with dereferencing */ @Test public void testMatchVarWithStarBefore() throws Throwable { final String exprString = "=*ptrvar"; final String[] children = new String[] { "ptrvar" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that variables can be dereferenced using '*' * without conflicting with glob-expressions */ @Test public void testDerefVar() throws Throwable { final String exprString = "*ptrvar"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); assertEquals(getExpressionValue(exprDmc), "0x12"); } /** * Test that variables can be matched using '*' at the end * not to be confused with multiplication */ @Test public void testMatchVarWithStarAfter() throws Throwable { final String exprString = "=var*2"; final String[] children = new String[] { "var2" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that variables can be multiplied using '*' * without conflicting with glob-expressions */ @Test public void testMultiplyVar() throws Throwable { final String exprString = "var*0"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); assertEquals(getExpressionValue(exprDmc), "0x0"); } /** * Test that registers can be matched using '?' */ @Test public void testMatchRegWithQuestionMark() throws Throwable { final String exprString = "=$f????"; final String[] children = new String[] { "$fctrl", "$fioff", "$fiseg", "$fooff", "$foseg", "$fstat" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that conditional operator can be used for registers */ @Test public void testRegWithConditionalOperator() throws Throwable { final String exprString = "$es?0x16:0x11"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); assertEquals(getExpressionValue(exprDmc), "0x11"); } /** * Test that variables can be matched using '?' */ @Test public void testMatchVarWithQuestionMark() throws Throwable { final String exprString = "=?ar?"; final String[] children = new String[] { "var2" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that conditional operator can be used with variables */ @Test public void testVarWithConditionalOperator() throws Throwable { final String exprString = "var?0x16:0x11"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); assertEquals(getExpressionValue(exprDmc), "0x16"); } /** * Test that registers can be matched using [] with a single number. * There should be no confusion about array index for registers. */ @Test public void testMatchRegWithOneDigitRange() throws Throwable { final String exprString = "=$st[4]"; final String[] children = new String[] { "$st4" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that registers can be matched using [] with a single letter. * There should be no confusion about array index for registers. */ @Test public void testMatchRegWithOneLetterRange() throws Throwable { final String exprString = "=$xmm[0]"; final String[] children = new String[] { "$xmm0" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that registers can be matched using [] using a range of numbers * There should be no confusion about array index for registers. */ @Test public void testMatchRegWithNumberRange() throws Throwable { final String exprString = "=$st[2-5]"; final String[] children = new String[] { "$st2","$st3", "$st4","$st5" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that registers can be matched using [] using a range of letters * There should be no confusion about array index for registers. */ @Test public void testMatchRegWithLetterRange() throws Throwable { final String exprString = "=$fo[a-z]"; final String[] children = new String[] { "$fop" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that registers can be matched using [] using a range of letters * and a * pattern */ @Test public void testMatchRegWithComplexLetterRange() throws Throwable { final String exprString = "=$fo[o-p]*"; final String[] children = new String[] { "$fooff", "$fop" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be matched using [] using a range of numbers. * In this case, we want to show the user the range of array elements. */ @Test public void testMatchArrayWithNumberRange() throws Throwable { final String exprString = "=array[2-5]"; final String[] children = new String[] { "array2", "array3", "array[2]","array[3]", "array[4]","array[5]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be matched using [] using a single number range. */ @Test public void testMatchArrayWithSingleNumberRange() throws Throwable { final String exprString = "=array[2]"; final String[] children = new String[] { "array2", "array[2]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be matched using [] using a number range * using the same number. */ @Test public void testMatchArrayWithSameNumberRange() throws Throwable { final String exprString = "=array[2-2]"; final String[] children = new String[] { "array2", "array[2]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be accessed using subtraction. * No matching should be performed here, and the result should * be the array element based on the subtraction result. */ @Test public void testArrayWithSubtraction() throws Throwable { final String exprString = "array[5-3]"; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); assertEquals(getExpressionValue(exprDmc), "0x16"); } /** * Test that arrays can be matched using [] and a wildcard. */ @Test public void testMatchArrayWithWildCardAndNumberRange() throws Throwable { final String exprString = "=ar*[2-3]"; final String[] children = new String[] { "array2", "array3", "arrayBool[2]", "arrayBool[3]", "arrayInt[2]", "arrayInt[3]", "array[2]", "array[3]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be matched using [] and a ?. */ @Test public void testMatchArrayWithQuestionMarkAndNumberRange() throws Throwable { final String exprString = "=ar?a?[2-4]"; final String[] children = new String[] { "array2", "array3", "array[2]","array[3]", "array[4]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match all arrays using []. * In this case, we want to show the user the range of array elements. */ @Test public void testMatchAllArraysAndNumberRange() throws Throwable { final String exprString = "=*[2-3]"; final String[] children = new String[] { "array2", "array3", "arrayBool[2]", "arrayBool[3]", "arrayInt[2]", "arrayInt[3]", "array[2]", "array[3]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match arrays using [] and comma-separated indices. */ @Test public void testMatchArraysWithCommaSeparatedIndices() throws Throwable { final String exprString = "=array[2,5,8]"; final String[] children = new String[] { "array2", "array[2]", "array[5]", "array[8]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match arrays using [] and comma-separated ranges. */ @Test public void testMatchArraysWithCommaSeparatedNumberRanges() throws Throwable { final String exprString = "=array[2-3, 5, 7-8]"; final String[] children = new String[] { "array2", "array3", "array[2]", "array[3]", "array[5]", "array[7]", "array[8]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match arrays using [] and comma-separated ranges * with an overlap. */ @Test public void testMatchArraysWithCommaSeparatedOverlappingRanges() throws Throwable { final String exprString = "=array[2-3, 5, 4-6]"; final String[] children = new String[] { "array2", "array3", "array[2]", "array[3]", "array[4]", "array[5]", "array[6]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match arrays using [] and comma-separated ranges * that are not sorted. */ @Test public void testMatchArraysWithCommaSeparatedUnsortedRanges() throws Throwable { final String exprString = "=array[5-6, 3, 0-1]"; final String[] children = new String[] { "array3", "array[0]", "array[1]", "array[3]", "array[5]", "array[6]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match arrays using [] and comma-separated ranges * containing invalid ranges. Invalid ranges are not accepted by * regular expressions and therefore will be ignored for the name. * I.e., array2 and array3 will not be matches, but only array indices * will be matched. */ @Test public void testMatchArraysWithCommaSeparatedInvalidRanges() throws Throwable { final String exprString = "=array[2-3, 5, 6-4]"; final String[] children = new String[] { "array[2]", "array[3]", "array[5]", "array[6-4]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we properly handle a non-arrays when using [] */ @Test public void testMatchNonArrayWithNumberRange() throws Throwable { final String exprString = "=arrayNot[2-3]"; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildrenCount(exprDmc, 0); } /** * Test that arrays can be accessed using [] with a single letter range. * In this case, since letters do not indicate an array index, * we match a letter range within the _name_ of the array. */ @Test public void testMatchArrayWithSingleLetterRange() throws Throwable { final String exprString = "=array[B]*"; final String[] children = new String[] { "arrayBool" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be accessed using [] with a letter range. * In this case, since letters do not indicate an array index, * we match a letter range within the _name_ of the array. */ @Test public void testMatchArrayWithLetterRange() throws Throwable { final String exprString = "=array[B-I]*"; final String[] children = new String[] { "arrayBool", "arrayInt" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be accessed using [] with a letter range. * In this case, since letters do not indicate an array index, * we match a letter range within the _name_ of the array. */ @Test public void testMatchArrayWithLetterRange2() throws Throwable { final String exprString = "=ar*[B-I]*"; final String[] children = new String[] { "arrayBool", "arrayInt" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that arrays can be accessed using [] with an invalid range. * In this case, the range is used as-is to create the expression. */ @Test public void testMatchArrayWithInvalidNumberRange() throws Throwable { final String exprString = "=array[5-2]"; final String[] children = new String[] { "array[5-2]" }; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that all registers and all locals can be matched at the same time */ @Test public void testGroupAllRegsAllLocals() throws Throwable { final String exprString = "$*; *"; List<String> list = get_X86_REGS(); Collections.sort(list); list.addAll(Arrays.asList(fAllVariables)); final String[] children = list.toArray(new String[list.size()]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that all local and all registers can be matched at the same time. This * is the reverse order than the previous test. */ @Test public void testGroupAllLocalsAllRegs() throws Throwable { final String exprString = "*; $*"; List<String> list = get_X86_REGS(); Collections.sort(list); list.addAll(0, Arrays.asList(fAllVariables)); final String[] children = list.toArray(new String[list.size()]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can match a range */ @Test public void testGroupSubExprRange() throws Throwable { final String exprString = "$eax; $es; *"; final String[] children = new String[] { "$es", "firstarg", "firstvar", "ptrvar" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); // Check four children starting at position 1 checkChildren(exprDmc, 1, 4, children); } /** * Test that we can group a local with all registers */ @Test public void testGroupOneLocalAllReg() throws Throwable { final String exprString = "firstvar; $*"; List<String> list = get_X86_REGS(); Collections.sort(list); list.addAll(0, Arrays.asList(new String[] { "firstvar" })); final String[] children = list.toArray(new String[list.size()]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we can group a local with a pattern for variables */ @Test public void testGroupOneLocalMatchedLocals() throws Throwable { final String exprString = "*ptrvar; =var*"; final String[] children = new String[] { "*ptrvar", "var", "var2" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we only return a single instance of a duplicate * register when using a pattern that matches the register * more than once. */ @Test public void testUniqueWhenOverlapReg() throws Throwable { final String exprString = "=$fioff; =$f?off; =$fo*"; final String[] children = new String[] { "$fioff","$fooff","$fop","$foseg" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that we only return a single instance of a duplicate * variable when using a pattern that matches the variable * more than once. */ @Test public void testUniqueWhenOverlapLocal() throws Throwable { final String exprString = "firstvar;*;firstvar"; final String[] children = new String[] { "firstvar", "firstarg", "ptrvar", "secondarg", "secondvar", "var", "var2" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that the all-register pattern is sorted alphabetically */ @Test public void testSortedAllReg() throws Throwable { final String exprString = "$*"; List<String> regList = get_X86_REGS(); Collections.sort(regList); final String[] children = regList.toArray(new String[0]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that the all-local pattern is sorted alphabetically */ @Test public void testSortedAllLocals() throws Throwable { final String exprString = "*"; List<String> list = Arrays.asList(fAllVariables); Collections.sort(list); final String[] children = list.toArray(new String[list.size()]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that individual expressions within a group-expression * are not sorted between each other, but that each part of the * group is kept in the user-specified order and sorted within * itself. */ @Test public void testSeparatlySorted() throws Throwable { final String exprString = "$*; *"; List<String> list = get_X86_REGS(); Collections.sort(list); List<String> localsList = Arrays.asList(fAllVariables); Collections.sort(localsList); list.addAll(localsList); final String[] children = list.toArray(new String[list.size()]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that pattern-matched arrays are sorted properly by index instead * of completely alphabetically. An alphabetical sorting would cause the * following poor sorting: * =a[1-11] * a[10] * a[11] * a[1] * a[2] * ... */ @Test public void testArraySorting() throws Throwable { final String exprString = "=array[1-11];=arrayInt[1-2,11,20-22]"; final String[] children = new String[] { "array[1]","array[2]","array[3]","array[4]","array[5]","array[6]", "array[7]","array[8]","array[9]","array[10]","array[11]", "arrayInt[1]","arrayInt[2]","arrayInt[11]","arrayInt[20]","arrayInt[21]","arrayInt[22]"}; SyncUtil.runToLocation("testArrayMatching"); MIStoppedEvent stoppedEvent = SyncUtil.step(6, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } // Cannot use comma separator because of templates (bug 393474) // /** // * Test that group-expression can use a comma as a separator // */ // @Test // public void testCommaSeparation() throws Throwable { // final String exprString = "firstvar,$eax"; // final String[] children = new String[] { "firstvar","$eax" }; // // SyncUtil.runToLocation("foo"); // MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); // // IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // // final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); // // checkChildren(exprDmc, -1, -1, children); // checkChildrenCount(exprDmc, children.length); // } /** * Test that group-expression can use a semi-colon as a separator */ @Test public void testSemiColonSeparation() throws Throwable { final String exprString = "firstvar;$eax"; final String[] children = new String[] { "firstvar","$eax" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that a valid expression that contains a comma will not be converted * to a group expression (bug 393474) */ @Test public void testExpressionWithCommand() throws Throwable { // The following expression is a valid one for a program using templates. // We will check that it does not get split into two expressions. final String exprStringComma = "((((((class std::_Vector_base<int, std::allocator<int> >) v))._M_impl))._M_start)"; // The following expression is not valid. However, it is identical to the previous // one except it uses a semi-colon. We use it to confirm that such an expression // will be treated as a group-exrepssion and get split into two children. // This is a way to confirm that the test is valid for the above expression that // is separated by a command. final String exprStringSemiColon = exprStringComma.replace(',', ';'); assertFalse("The two strings for this test should not be the same", exprStringComma.equals(exprStringSemiColon)); MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("foo"); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmcSemiColon = SyncUtil.createExpression(frameDmc, exprStringSemiColon); final IExpressionDMContext exprDmcComma = SyncUtil.createExpression(frameDmc, exprStringComma); try { // This should get split into two children and not // sent to GDB at all, so we should not see a failure, // even though the expression is not valid for the // program we are debugging. checkChildrenCount(exprDmcSemiColon, 2); } catch (Exception e) { assertFalse("Expected two children for when using a semi-colon", true); } try { // Should throw an exception because this expression is not // valid and since it does not get split into children, // we'll be sending to GDB and seeing the failure. checkChildrenCount(exprDmcComma, 0); } catch (Exception e) { // Valid and expected return; } // Should not get here assertFalse("Should have seen an expression thrown", true); } // Cannot use comma separator because of templates (bug 393474) // /** // * Test that group-expression can use a comma and a semi-colon as a // * separator at the same time // */ // @Test // public void testCommaAndSemiColonSeparation() throws Throwable { // final String exprString = "firstvar,$eax;$es"; // final String[] children = new String[] { "firstvar","$eax","$es" }; // // SyncUtil.runToLocation("foo"); // MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); // // IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // // final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); // // checkChildren(exprDmc, -1, -1, children); // checkChildrenCount(exprDmc, children.length); // } // Cannot use comma separator because of templates (bug 393474) // /** // * Test that group-expression can have empty terms with commas. // */ // @Test // public void testGroupCommaEmptyTerm() throws Throwable { // final String exprString = ",,firstvar,,$eax,,"; // final String[] children = new String[] { "firstvar","$eax" }; // // SyncUtil.runToLocation("foo"); // MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); // // IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); // // final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); // // checkChildren(exprDmc, -1, -1, children); // checkChildrenCount(exprDmc, children.length); // } /** * Test that group-expression can have empty terms with semi-colon. */ @Test public void testGroupSemiColonEmptyTerm() throws Throwable { final String exprString = ";;firstvar;;$eax;;"; final String[] children = new String[] { "firstvar","$eax" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test that group-expression clean up extra spaces */ @Test public void testExtraSpaces() throws Throwable { final String exprString = " firstvar ; $eax ; ; =var? ; = second* "; final String[] children = new String[] { "firstvar","$eax","var2","secondarg","secondvar" }; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); checkChildren(exprDmc, -1, -1, children); checkChildrenCount(exprDmc, children.length); } /** * Test the expression data associated with group-expressions. */ @Test public void testGroupExpressionData() throws Throwable { final String exprString = "$eax;*"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); Query<IExpressionDMData> query = new Query<IExpressionDMData>() { @Override protected void execute(final DataRequestMonitor<IExpressionDMData> rm) { fExpService.getExpressionData(exprDmc, rm); } }; fSession.getExecutor().execute(query); IExpressionDMData data = query.get(); Query<IExpressionDMDataExtension> query2 = new Query<IExpressionDMDataExtension>() { @Override protected void execute(final DataRequestMonitor<IExpressionDMDataExtension> rm) { fExpService.getExpressionDataExtension(exprDmc, rm); } }; fSession.getExecutor().execute(query2); IExpressionDMDataExtension dataExt = query2.get(); // Make sure the two different ways to get the group-expression data return // the same thing, to make sure we didn't forget to update one of the two. assertEquals(data, dataExt); assertEquals(exprString, dataExt.getName()); assertEquals(IExpressionDMData.BasicType.array, dataExt.getBasicType()); assertEquals("Group-pattern", dataExt.getTypeName()); assertTrue("IExpressionDMDataExtension.HasChildren should have been true", dataExt.hasChildren()); assertEquals("Group-pattern", dataExt.getTypeName()); } /** * Test the expression address data associated with group-expressions. */ @Test public void testGroupExpressionAddressData() throws Throwable { final String exprString = "$eax;*"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() { @Override protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) { fExpService.getExpressionAddressData(exprDmc, rm); } }; fSession.getExecutor().execute(query); IExpressionDMAddress data = query.get(); assertTrue("The address data shoudl be of type IExpressionDMLocation", data instanceof IExpressionDMLocation); assertEquals(IExpressions.IExpressionDMLocation.INVALID_ADDRESS, data.getAddress()); assertEquals(0, data.getSize()); assertEquals("", ((IExpressionDMLocation)data).getLocation()); } /** * Test the call to IExpressions.getSubExpressions(IExpressionDMC, DRM); * which is not tested by the method checkChildren() used by our other tests */ @Test public void testGroupGetSubExpressions() throws Throwable { final String exprString = "$eax;*"; List<String> list = new LinkedList<String>(); list.add("$eax"); list.addAll(Arrays.asList(fAllVariables)); final String[] children = list.toArray(new String[list.size()]); SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); Query<IExpressionDMContext[]> query = new Query<IExpressionDMContext[]>() { @Override protected void execute(final DataRequestMonitor<IExpressionDMContext[]> rm) { fExpService.getSubExpressions(exprDmc, rm); } }; fSession.getExecutor().execute(query); IExpressionDMContext[] childDmcs = query.get(); 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(children) + " but got " + Arrays.toString(childExpressions), children.length == childExpressions.length); for (int i = 0; i < childDmcsAccessor.length; i++) { assertEquals(childDmcsAccessor[i].getRelativeExpression(), children[i]); } } /** * Test we cannot modify the value of a group-expression */ @Test public void testGroupExpressionNotModifiable() throws Throwable { final String exprString = "$eax;*"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); Query<Boolean> query = new Query<Boolean>() { @Override protected void execute(final DataRequestMonitor<Boolean> rm) { fExpService.canWriteExpression(exprDmc, rm); } }; fSession.getExecutor().execute(query); boolean canWrite = query.get(); assertFalse("Should not be able to modify the value of a group-expression", canWrite); } /** * Test the only available format for the value of a group-expression is NATURAL */ @Test public void testGroupExpressionAvailableFormats() throws Throwable { final String exprString = "$eax;*"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, exprString); Query<String[]> query = new Query<String[]>() { @Override protected void execute(final DataRequestMonitor<String[]> rm) { fExpService.getAvailableFormats(exprDmc, rm); } }; fSession.getExecutor().execute(query); String[] formats = query.get(); assertEquals(1, formats.length); assertEquals(IFormattedValues.NATURAL_FORMAT, formats[0]); } /** * Test the different values returned by a group-expression */ @Test public void testGroupExpressionValue() throws Throwable { final String noMatchExpr = "=$zzz*"; final String singleMatchExpr = "=$ds;"; final String doubleMatchExpr = "=$ds;=$es"; SyncUtil.runToLocation("foo"); MIStoppedEvent stoppedEvent = SyncUtil.step(5, StepType.STEP_OVER); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IExpressionDMContext noMatchExprDmc = SyncUtil.createExpression(frameDmc, noMatchExpr); final IExpressionDMContext singleMatchExprDmc = SyncUtil.createExpression(frameDmc, singleMatchExpr); final IExpressionDMContext doubleMatchExprDmc = SyncUtil.createExpression(frameDmc, doubleMatchExpr); assertEquals("No matches", getExpressionValue(noMatchExprDmc)); assertEquals("1 unique match", getExpressionValue(singleMatchExprDmc)); assertEquals("2 unique matches", getExpressionValue(doubleMatchExprDmc)); } }